MQTT QoS (Quality of Service) defines how hard the protocol tries to deliver a message. There are three QoS levels — 0, 1 and 2 — and each adds acknowledgement packets in exchange for a stronger guarantee. Picking the right level is one of the most important design decisions in an MQTT system: too low and you lose data, too high and you waste bandwidth and latency.
QoS levels at a glance
| QoS | Guarantee | Packets per hop | Duplicates possible? |
|---|---|---|---|
| 0 | At most once | 1 (PUBLISH) | No — but messages may be lost |
| 1 | At least once | 2 (PUBLISH, PUBACK) | Yes |
| 2 | Exactly once | 4 (PUBLISH, PUBREC, PUBREL, PUBCOMP) | No |
An important detail: QoS is negotiated per hop. The publisher's QoS governs the trip to the broker, and the subscription's QoS governs the trip from the broker to each subscriber.
QoS 0 — at most once
The sender transmits the PUBLISH once and forgets about it. There is no acknowledgement and no packet identifier. If the TCP connection breaks while the message is in flight, it is gone.
Sender Receiver
| ---- PUBLISH (QoS 0) ---> |
| | (no reply)QoS 0 is the cheapest option and perfectly fine for high-frequency telemetry — a temperature reading every second, a GPS position, a heartbeat — where the next message supersedes the one that was lost. Note that TCP still protects against corruption and reordering on a live connection; the risk is losing messages when connections drop.
QoS 1 — at least once
The sender assigns a packet identifier, stores the message and waits for a PUBACK with the same identifier. Until the acknowledgement arrives, the message is considered in flight. If the connection drops first, the sender retransmits it with the DUP flag set when the session resumes.
Sender Receiver
| ---- PUBLISH (QoS 1, id=7) ---> | store + deliver
| <--------- PUBACK (id=7) ------ |
| delete stored message |The catch: if the PUBACK is lost, the receiver has already processed the message and gets it again on retransmission. QoS 1 therefore guarantees delivery but allows duplicates. For most applications that is the right trade-off — make your handlers idempotent (for example, by including a message ID or timestamp in the payload) and you get reliability with low overhead.
QoS 2 — exactly once
QoS 2 uses a four-step handshake so that neither side can deliver the message twice:
Sender Receiver
| ---- PUBLISH (QoS 2, id=9) ---> | store id=9, (deliver)
| <--------- PUBREC (id=9) ------ |
| ---------- PUBREL (id=9) -----> | release id=9
| <--------- PUBCOMP (id=9) ----- |
| done |PUBLISH— the sender transmits the message and keeps a copy.PUBREC— the receiver confirms receipt and records the packet identifier. Any retransmittedPUBLISHwith that identifier is recognised as a duplicate and not delivered again.PUBREL— the sender discards the message and tells the receiver it may release the identifier.PUBCOMP— the receiver confirms; the identifier can be reused.
The cost is two round trips per hop and state on both sides. QoS 2 makes sense for messages where a duplicate is actually harmful and cannot be filtered in the application — billing events or one-shot actuator commands, for example. In practice many teams use QoS 1 plus deduplication instead.
The downgrade rule: effective QoS
A subscriber requests a maximum QoS in its SUBSCRIBE packet, and the broker returns the granted QoS in SUBACK. Each message is then delivered at the lower of the publish QoS and the granted subscription QoS:
| Published with | Subscribed with | Delivered with |
|---|---|---|
| QoS 2 | QoS 0 | QoS 0 |
| QoS 1 | QoS 2 | QoS 1 |
| QoS 0 | QoS 1 | QoS 0 |
| QoS 2 | QoS 2 | QoS 2 |
Brokers may also cap QoS: in MQTT 5 a broker can advertise Maximum QoS in CONNACK, and some brokers or cloud services do not support QoS 2 at all. Always check the granted QoS in the SUBACK rather than assuming you got what you asked for.
QoS and sessions: what happens offline
QoS only protects messages while a session exists. With a clean session (cleanSession=true in 3.1.1, cleanStart=true with a session expiry of 0 in MQTT 5), the broker throws away subscriptions and pending messages as soon as the client disconnects — so QoS 1 and 2 messages published while you are offline are simply never delivered to you.
To receive messages that arrive while a client is offline, you need all three of:
- a stable, unique client ID,
- a persistent session (
cleanSession=false, or in MQTT 5 a non-zeroSession Expiry Interval), - a subscription with QoS 1 or 2, and messages published with QoS 1 or 2.
Also note that retransmission of unacknowledged messages happens when the session resumes after a reconnect — neither 3.1.1 nor 5.0 requires resending on a live connection, because TCP already handles loss there.
Testing QoS in practice
You can watch QoS in action with the Mosquitto CLI. The -d flag prints every packet, so you can see PUBREC/PUBREL/PUBCOMP go by:
# subscriber with a persistent session (-c) and fixed client ID
mosquitto_sub -h broker.emqx.io -t 'testmqtt/qos-demo/#' -q 2 -c -i qos-demo-sub -d
# publish at QoS 2
mosquitto_pub -h broker.emqx.io -t 'testmqtt/qos-demo/order' -m 'order-1001' -q 2 -dStop the subscriber, publish a few QoS 1 messages, then start it again with the same client ID: the queued messages should arrive. In the browser, the online MQTT client lets you pick QoS per subscription and per publish. For more test scenarios see how to test an MQTT broker.
Try it in the online MQTT client
Choosing a QoS level
- QoS 0 — frequent sensor data, positions, metrics where only the latest value matters.
- QoS 1 — the sensible default for events, alerts and commands; pair it with idempotent handlers.
- QoS 2 — rare cases where duplicates are costly and cannot be deduplicated downstream.
QoS works hand in hand with retained messages and Last Will; if you are new to the protocol, start with what is MQTT.
Frequently asked questions
Which MQTT QoS level should I use?
Use QoS 0 for frequent telemetry where a lost sample does not matter, QoS 1 for most events and commands (and make handlers idempotent), and QoS 2 only when duplicates are genuinely harmful and you cannot deduplicate in the application.
Why did I receive a QoS 1 message twice?
QoS 1 is at-least-once delivery. If the acknowledgement is lost, typically because the connection dropped, the sender retransmits the message with the DUP flag set after reconnecting, so the receiver can see it twice.
Does QoS 2 guarantee end-to-end exactly-once delivery?
No. QoS applies to each hop separately: publisher to broker and broker to subscriber. The subscriber receives the minimum of the publish QoS and its subscription QoS, and messages for offline clients are only kept if they have a persistent session.