In this article, we will explore how to map MQTT QoS levels to IoT risks by breaking down 3 QoS levels of IoT communications and determining which QoS level best fits each risk category. We will conclude by using an example to piece these risk and QoS mappings together to select an appropriate MQTT QoS level for a specific IoT system.
MQTT QoS 0 – At Most Once: This QoS level best fits IoT data that can be easily discarded if lost or duplicated, and where it would be difficult to know whether a message was lost or duplicated. Examples of this data are temperature measurements from a distributed array of temperature sensors and water leak sensors in a home. Discarding one of these measurements or one of these notifications does not matter. It would be difficult to know whether the one missed temperature reading or notification was truly lost or if it was just duplicated.
MQTT QoS 1 – At Least Once: This QoS level best fits IoT data that must be received by the receiver but where duplicate data can be handled. Examples of this data are temperature readings from a distributed array of temperature sensors and water leak sensors in a home. In contrast to QoS 0 above, these temperature measurements and leak notifications must be received by the receiving system so the receiving system can make a decision to heat or cool the home or to shut off water to the home if a leak is detected. The receiving system must be prepared to handle duplicate data.
MQTT QoS 2 – Exactly Once: This QoS level best fits IoT data where a missing data packet or a duplicate data packet would be bad. An example of this data is the amount of gas in a gas tank of a car. Discarding one of the gas level measurements would be bad because a car with an incorrect gas level indication might run out of gas and stop on the road. Duplicate gas level measurements would be bad because the car driver might not know how much gas is in the gas tank. A driver might not fill up the gas tank because he or she thinks the gas tank is more full than it really is. This bad driver might run out of gas and stop on the road.
Let’s now put all of this information together to determine the appropriate MQTT QoS level to use for an IoT system where a distributed array of temperature sensors and water leak sensors continuously send temperature and water leak information to a receiving system to decide when to turn heating or cooling on or off and when to turn off water supply to home. We will first list all of the information types and their associated risks, and then we will select an MQTT QoS level for each of these information types.
| Data Type | Associated Risk | MQTT QoS Level to Use |
|---|---|---|
| Temperature measurement from temp. sensors | Not bad to lose one of these measurements or to duplicate one of these measurements. These would be difficult to know if lost or duplicated. | MQTT QoS 0 |
| Water leak sensor notification from leak sensors | Not bad to lose one of these notifications or to duplicate one of these notifications. These would be difficult to know if lost or duplicated. | MQTT QoS 0 |
| Decision to turn heating or cooling on or off | Bad to lose the heating or cooling on or off decision. Must receive the decision. System must be prepared to handle duplicate heating or cooling on or off decisions. | MQTT QoS 1 |
| Decision to turn off water supply to home | Bad to lose the decision to turn off water supply to home. Must receive the decision. System must be prepared to handle duplicate decisions to turn off water supply to home. | MQTT QoS 1 |
This now leaves us with a choice. For the information sent to this system from the sensors, do we use MQTT QoS 0 for all of this information, or do we use MQTT QoS 1 for all of this information. For the information sent to this system from the decision making system, do we use MQTT QoS 1 for all of this information, or do we use MQTT QoS 2 for all of this information. The decision to use MQTT QoS 0 or MQTT QoS 1 for information coming from the sensors to the system and to use MQTT QoS 1 or MQTT QoS 2 for information coming from the system to the actuators is a decision which must be based on how critical each type of information is to the safety of the people and things in and around the home and the costs of implementing the solution to ensure the information gets to the receiving system with the appropriate level of guarantees of delivery.
MQTT has three levels of quality of service (QoS). QoS 0 is at most once, QoS 1 is at least once (duplicate messages are possible), and QoS 2 is exactly once via a four-step handshake. For most IoT workloads, the default QoS level should be 1 unless your scale demands the higher throughput of QoS 0 or your duplicate message tolerance demands the stronger guarantees of QoS 2. OASIS MQTT specification
TL;DR:
Use QoS 1 for most IoT messages because, unless ultra low latency is required or some loss is acceptable, QoS 1 provides an optimal compromise between delivery guarantees and overhead.
Keep in mind that QoS is negotiated per hop, so if a subscriber asks for QoS 0, they may actually receive messages at a lower level of guarantee than that of the publisher.
- Do not rely on MQTT packet identifiers for deduplication at QoS 1 or 2; they may wrap across sessions or reconnects.
- Use QoS 2 only for important transactions such as billing or financial information where strict exactly-once delivery is required. Add application-level idempotency.
In order to avoid these issues, persistent sessions, correct session configuration and storage of message IDs should be implemented before the application goes into production.
PODTECH
Build More Reliable IoT Telemetry
PODTECH creates custom software, automation, and intelligent monitoring solutions for mission-critical infrastructure environments.
Learn more about PODTECHTable of Contents
- What are MQTT QoS levels and why do they matter?
- QoS 0: the flow, its failure modes, and when to use it
- QoS 1: the PUBACK handshake and why duplicates happen
- QoS 2: the exactly-once handshake and its real cost
- How does effective QoS and downgrade behaviour work?
- What are the performance trade-offs for common IoT streams?
- What implementation pitfalls should you check before going live?
- PODTECH’s practitioner notes on choosing QoS in enterprise telemetry
- Three rules for MQTT reliability worth adopting
- How PODTECH supports reliable MQTT telemetry projects
- Sources
- FAQ
What are MQTT QoS levels and why do they matter?
Quality of service (QoS) in MQTT is an agreement between a publisher, the broker, and a subscriber on how hard the protocol should work to deliver a given message. QoS is not a single, one-size-fits-all setting for your entire system. Each message has its own QoS flag and the OASIS MQTT 5.0 spec outlines the exact packet flow for each level in Section 4.3.
Here's the bit that most tutorials gloss over: QoS is negotiated hop by hop, not end to end. A publisher transmits at QoS 2, but the subscriber connects at QoS 0, the broker will deliver at the lower of the two. That is the effective QoS rule and it trips up developers who assume that setting QoS 2 on publish will ensure exactly-once delivery all the way to their application.
A few things follow from that scope:
- QoS is a guarantee between client and broker, not a guarantee about what your backend does with the message after that point.
- Transport-layer reliability is decoupled from MQTT acknowledgement flows. TCP guarantees bytes delivered on an open connection; MQTT QoS persists through reconnects and broker restarts, which is not possible with TCP alone.
- Higher QoS trades delivery guarantee for overhead in the form of round trips, broker memory and client-side state.
QoS 0: the flow, its failure modes, and when to use it
QoS 0 is a single PUBLISH packet with no acknowledgement. The publisher sends it, the broker forwards it, and nobody checks if it arrived. Mosquitto’s own documentation calls this fire-and-forget delivery, and the description is apt: after the packet has left the sender there is no way to confirm, retry, or recover it.
That absence of an ACK creates three distinct points of failure:
- Publisher to broker: if the network drops the packet mid-transit, it’s simply gone.
- Broker crash or restart: any QoS 0 message in flight when the broker goes down is lost, as it is not queued up to replay from.
- Subscriber offline: a disconnected subscriber never receives the message, and no persistent session will queue it, because QoS 0 messages aren’t held for delivery on reconnect.
However, that doesn't mean QoS 0 is always wrong. Sensor telemetry with a high message rate is such a case where the next value is going to be available in a second or two at the latest. There's no need to guarantee that every single packet is received. A temperature feed sent every 500 milliseconds can drop the occasional sample unnoticed.
Pro Tip: If you're publishing high-frequency telemetry over QoS 0, publish a heartbeat or sequence counter along with the data. It can't be used to recover lost messages, but it will allow your dashboard to flag gaps instead of silently displaying stale values as current.
QoS 1: the PUBACK handshake and why duplicates happen
QoS 1 introduces a single acknowledgement step. The publisher transmits PUBLISH, the receiver replies with PUBACK, and if that PUBACK is not received in time, the publisher retransmits the original message with DUP flag set. HiveMQ has a great MQTT Essentials guide that describes this handshake very clearly: it ensures that the message is delivered at least once, but “at least once” is doing heavy lifting in that sentence.
Duplicates occur exactly because the acknowledgement itself can be lost. The broker may have received the message and handled it just fine, but if the PUBACK never returns to the publisher, the publisher thinks it failed and resends. Your subscriber receives the same message twice.
Handling this well means:
- Assigning each logical message a unique ID at the application layer, independent from MQTT packet identifiers which are reused over the lifetime of a connection.
- Verifying that ID against an ephemeral or durable cache before processing, to discard duplicates rather than double-count.
- Allowing for persistent sessions by setting clean session to false, or in MQTT 5 using the session expiry interval mechanism, so that QoS 1 messages queued for an offline subscriber will actually be delivered when it reconnects instead of being dropped.
QoS 1 is right for the majority of command-and-control traffic: turning a valve, sending a config change, triggering an actuator. Dropping the message is not an option, but receiving it twice is an inconvenience you can work around.
Pro Tip: Do not use the MQTT packet identifier as the key to your deduplication lookup. It is connection-scoped and will be recycled, meaning that two completely different messages can have the same packet ID at different times during a session.
QoS 2: the exactly-once handshake and its real cost
QoS 2 replaces the single acknowledgement with a four-message exchange, and it’s worth stepping through in order:
- PUBLISH: the publisher sends the message with a QoS 2 flag and a packet identifier.
- PUBREC: the receiver stores the message and responds to confirm receipt.
- PUBREL: the sender, having received PUBREC, tells the receiver that it's now safe to release and forget the original PUBLISH, since it's been safely stored by the receiver.
- PUBCOMP: the receiver confirms the release, and the transaction closes.
This 4-step handshake exists solely to prevent duplicates at the protocol layer, and the HiveMQ article is quite blunt about the tradeoff: exactly-once at the protocol layer costs approximately four times the round trips of QoS 0, as well as persistent state on both ends of the connection until PUBCOMP completes the handshake.
That's important because of the state requirement rather than the latency. Both broker and client must keep state for in-flight QoS 2 messages, and packet identifiers must persist through a restart in order for the handshake to pick up cleanly, which the OASIS spec calls out directly under session state.
The caveat that trips people up: QoS 2 only ensures that the broker and the client code path handles the message exactly-once. QoS 2 doesn't ensure your application logic itself acts on a given message exactly-once. If your backend persists a write to a database, and crashes after that write but before it acknowledges, you could still end up reprocessing a message on restart. Durable, production-ready exactly-once semantics involves a combination of QoS 2 plus application-level idempotency, usually a persistent store of processed message IDs, not QoS 2 by itself.
Use reserve QoS 2 only for things like billing events or money transfers where a duplicate is actually expensive, not just messy.
How does effective QoS and downgrade behaviour work?
It's easy to state and easy to forget when dealing with code: the effective QoS is always the minimum of the publisher's QoS and the subscriber's requested QoS (see Mosquitto documentation for confirmation). If a publisher is sending at QoS 2 to a broker, and one subscriber is only requesting QoS 0, then that subscriber will receive the message at QoS 0. Any other subscribers on the same topic, requesting QoS 2, will still get the full exactly-once treatment.
This produces genuinely different outcomes for different subscribers on the same message:
- A dashboard client subscribing with QoS 0 will receive messages with best-effort delivery, even if your device is configured to publish everything at QoS 2.
- A billing service subscribing at QoS 2 to that same topic gets the entire four-step guarantee whether or not any other subscribers requested that.
There is no one-to-one “QoS of the message”, as the broker services this on a per-subscription basis.
Ordering adds another wrinkle. MQTT preserves message order within a single QoS level on a single connection. It does not guarantee order across mixed QoS levels on the same topic, because a QoS 2 message’s four-step handshake simply takes longer to complete than a QoS 0 message sent moments later. If a device publishes a status update at QoS 0 immediately followed by an alarm at QoS 2, the QoS 0 message can arrive first even though it was sent second. For any stream where sequence matters, such as state transitions, keep every message on that topic at the same QoS level.
What are the performance trade-offs for common IoT streams?
The more QoS steps, the more packets, and the more packets, the more latency and broker load. QoS 0 requires 1 packet, QoS 1 requires 2 (PUBLISH and PUBACK), and QoS 2 requires 4, as seen in the handshake above. The independent guides all seem to agree on the same overhead pattern: for each additional round trip required, the broker also retains more in-flight state, and at fleet scale, that state adds up.
Storage requirements also scale differently. QoS 0 requires no persistent state on either side. QoS 1 requires the broker to store undelivered messages for any subscriber with a persistent session, until it reconnects and acknowledges. QoS 2 requires that plus tracking of packet identifiers through all four handshake stages, which is why brokers under heavy QoS 2 load use noticeably more memory per connection than the same volume of QoS 0 traffic.
A practical decision matrix, drawn from how EMQX’s guidance frames the trade-off:
- High-frequency sensor telemetry such as temperature, vibration, or GPS pings every few seconds: QoS 0. If we lose an occasional reading we don't change the trend line.
- Device commands and configuration changes such as actuator control, firmware trigger flags, or threshold updates: QoS 1, with application-level deduplication.
- Alarm and alert events such as equipment fault, safety trip, or threshold breach: QoS 1 at a minimum, often QoS 2 where a missed or duplicated alert has tangible consequences.
- Billing, metering, and financial events: QoS 2, with idempotent processing implemented on the backend.
At scale, this decision isn't academic. A fleet of ten thousand devices publishing telemetry at QoS 2 instead of QoS 0 multiplies broker memory and round-trip count by roughly four, for data where the guarantee adds no real value. Match the QoS to what the message actually needs, not to a blanket policy applied across every topic.
What implementation pitfalls should you check before going live?
The majority of MQTT reliability issues stem from a small number of common, repeatable errors. These are worth ticking off before production.
- Clean session left enabled by default. If a client connects with clean session true or, in MQTT 5, no session expiry interval configured, the broker will immediately discard any queued QoS 1 or QoS 2 messages as soon as that client disconnects. Teams often believe they are being protected by QoS 1, when in fact clean session is silently dropping everything queued during an outage. Persistence must be explicitly configured both on the client and the broker.
- Packet identifiers that don't survive a restart. In the case of QoS 2, packet IDs need to survive a client or broker crash for a handshake to correctly resume on reconnect. If a broker loses this state in the middle of a restart, it can result in either duplicate delivery or a handshake that gets stuck forever and never completes.
- No application-level deduplication store. QoS at level 1 or 2 is not enough, because your backend can itself fail partway through processing. A durable, persisted store of processed message IDs fills that gap.
- In-flight windows or queue depth aren't monitored. Rising PUBACK or PUBREC retransmit rates, or a persistent-queue size that continues to grow, can be early indicators of network congestion or a misconfigured client, and they're worth alerting on before they lead to a backlog or data loss.
Pro Tip: Intentionally test your reconnection logic in staging: terminate a subscriber's session in the middle of it, wait long enough after session expiry to force a reconnect, reconnect, and then verify messages that were sent in the meantime arrive in sequence. One such test will surface the majority of clean-session configuration problems before they hit production.
PODTECH’s practitioner notes on choosing QoS in enterprise telemetry
Enterprise telemetry systems almost never run a single QoS level end-to-end, and PODTECH’s engineering teams make the QoS-to-message-criticality map on each deployment. Dashboards for monitoring live rack temperature or PDU load, for example, run happily on QoS 0. Sensor values refresh every few seconds regardless, so a dropped reading here or there has no impact on operations. Alarm and fault conditions, on the other hand, are bumped to QoS 1, because the risk of missing a data hall alert is real and duplicate alerts are a tolerable nuisance.
Billing events, compliance logging, and the metering data that feeds into financial reporting sit at QoS 2, where PODTECH adds the handshake with persistent processed-ID stores instead of relying on the protocol layer alone. Over more than 250 delivered projects supporting a 99.9% uptime SLA, this stream-by-stream mapping, instead of a single default, is what keeps critical infrastructure telemetry fast and durable under load.
Three rules for MQTT reliability worth adopting
Three rules encompass most of what can go wrong with production MQTT deployments. Rule 1: Set your QoS to 1 unless you have a specific reason not to; rule 2: Validate your reconnect and clean session behavior on staging, don't wait for the first outage to tell you there's a hole in your deployment; rule 3: Monitor queue depth and retransmit rates at runtime, because they'll show congestion long before your users miss data.
Review these decisions when the number of devices or importance of messages changes significantly. A telemetry stream acceptable on QoS 0 with a hundred devices may require reevaluation at ten thousand.
— Harry
How PODTECH supports reliable MQTT telemetry projects
Designing QoS policy on paper is one thing. Operating it reliably on thousands of devices, dozens of brokers, and a legacy estate not designed for MQTT in mind is a different problem entirely, and it’s the one PODTECH solves for infrastructure operators every day.
Messaging architecture from PODTECH’s Datacenter Telemetry and Enterprise Automation Software teams are designed with QoS options, broker sizing, and session persistence built around actual fault tolerance requirements rather than a default configuration that has gone unexamined. If you are building a new monitoring layer from the ground up, SaaS Development and Product Development engagements cover the entire platform from the ingestion pipeline to the dashboard your operations team actually watches. If you are modernising a legacy telemetry stack that has outgrown its original design, PODTECH’s system integration work for other critical infrastructure clients has already charted the course for that transition. Reach out to PODTECH to request an architecture review of your current MQTT deployment.
Sources
MQTT has three different levels of Quality of Service:
MQTT supports 3 levels of QoS in the PUBLISH packets:
- QoS 0 - DELIVER AT MOST ONCE (fire and forget)
- QoS 1 - DELIVER AT LEAST ONCE (ACKs received)
- QoS 2 - DELIVER EXACTLY ONCE (ACKs received and confirmed)
What is MQTT Quality of Service (QoS) 0,1, & 2? – MQTT Essentials: Part 6 (HiveMQ)
FAQ
What Does MQTT QoS Level 2 Mean?
QoS 2 is MQTT’s exactly-once delivery guarantee, which is implemented with a four-step handshake process: PUBLISH, PUBREC, PUBREL and PUBCOMP. The receiver is prevented from processing a given message twice at the protocol level. Your application still needs its own idempotency checks to ensure exactly-once behaviour end to end.
Is MQTT Faster Than HTTP?
MQTT is typically faster and lighter than HTTP for ongoing IoT messaging. This is largely due to its persistent connection, rather than negotiating a handshake for every exchange. Of MQTT's three QoS levels, QoS 0 is the fastest, requiring only a single packet. The four-step handshake of QoS 2 incurs significantly more overhead per message.
What Are the Key Differences Between MQTT v3 and v5?
MQTT 5 includes reason codes on acknowledgement packets, shared subscriptions, message expiry intervals and richer session and error handling over prior versions. The fundamental QoS 0, 1 and 2 model and protocol flows are the same across versions in the OASIS spec.
What Are the Downsides of Using MQTT?
MQTT QoS guarantees apply on a per-hop basis rather than end-to-end by default, so developers making the mistake of trusting the protocol level to cover their entire application pipeline are vulnerable to failure. The increased resilience of higher QoS levels comes at a cost of increased persistent broker and client state, and misconfigured clean session often goes undetected as the root cause of missing messages which are blamed on the network.
When Should I Use QoS 0 Instead of QoS 1?
Use QoS 0 if it does not really matter if you lose a message every now and then. This is for example the case with high-frequency sensor telemetry where a new reading is coming in a few seconds anyway. Use QoS 1 if every message is important, like for commands, configuration updates, or alerts, and you can deal with an occasional duplicate at the application layer.
