Skip to content

How Sure Is Delivery? QoS

Scope: MQTT's three delivery promises — QoS 0, 1, and 2 — what each actually guarantees, and the packet exchanges that prove it, read from a real broker log. Verified against Mosquitto 2.0.21.

Three grades of promise

Every publish carries a Quality of Service level. It's a contract between the sender and the broker (and again between the broker and each subscriber): how hard everyone tries to deliver.

  • QoS 0 — at most once. "Fire and forget." The message is sent once; if it's lost on the way, it's gone. No acknowledgment, no retry.
  • QoS 1 — at least once. The sender keeps the message until the receiver acknowledges it (PUBACK), and resends if the acknowledgment doesn't come. Delivery is guaranteed; duplicates are possible if the acknowledgment is what got lost.
  • QoS 2 — exactly once. A four-step handshake (PUBREC, PUBREL, PUBCOMP) makes sure the message is delivered once and only once. The strongest promise, and the slowest.

The flag is -q to both clients. One subscriber asking for QoS 2, three publishes at the three levels:

mosquitto_sub -q 2 -t qos/test -v
mosquitto_pub -q 0 -t qos/test -m 'sent at QoS 0'
mosquitto_pub -q 1 -t qos/test -m 'sent at QoS 1'
mosquitto_pub -q 2 -t qos/test -m 'sent at QoS 2'

All three arrive. From the subscriber's chair the levels are indistinguishable — the difference is in the plumbing, which the broker's log shows if you run a broker with log_type all (the lab did exactly this on a side port). Publisher side, one line per packet:

QoS 0 — a single packet, no reply:

Received PUBLISH from auto-... (d0, q0, r0, m0, 'qos/test', ... (13 bytes))

QoS 1 — publish, then an acknowledgment back:

Received PUBLISH from auto-... (d0, q1, r0, m1, 'qos/test', ... (13 bytes))
Sending PUBACK to auto-... (m1, rc0)

QoS 2 — the four-step dance:

Received PUBLISH from auto-... (d0, q2, r0, m1, 'qos/test', ... (13 bytes))
Sending PUBREC to auto-... (m1, rc0)
Received PUBREL from auto-... (Mid: 1)
Sending PUBCOMP to auto-... (m1)

(The same exchanges repeat on the delivery side, between broker and subscriber, at the lower of the publish QoS and the subscription's QoS. A QoS 2 publish delivered to a QoS 0 subscription travels the last hop as QoS 0 — the promise only covers the legs that ask for it.)

Which to use

Level Guarantee Typical use
0 maybe once frequent sensor readings — the next one is seconds away and a gap doesn't matter
1 at least once (duplicates possible) commands, alerts, notifications — things that must arrive, where hearing it twice is harmless
2 exactly once rare: an action that must happen once and only once, when the extra chatter is worth it

Working rules of thumb:

  • Most real systems live at QoS 0 and 1. QoS 2's certainty costs four packets per message per hop, and "exactly once" rarely matters as much as people first think.
  • Duplicates at QoS 1 are not a bug — they're the price of the guarantee. Subscribers that act on commands should tolerate hearing one twice.
  • QoS is also what makes the broker hold messages for offline subscribers — which is the next chapter but one (Sessions and Queued Messages). A QoS 0 message for an absent subscriber is simply gone.