MQTT supports three QOS levels which are designed to ensure message delivery.
- QOS 0 – Once (not guaranteed)
- QOS 1 – At Least Once (guaranteed)
- QOS 2 – Only Once (guaranteed)
How they work is discussed in the understanding QOS tutorial.
In this article I want to delve more into the pros and cons of using these QOS levels and offer some guidelines on when to use them.
Using the default QOS 0
The default QOS for most MQTT clients is QOS 0. Using this level means that the message is sent once and that delivery isn’t guaranteed.
In general I use this QOS level wherever possible. It is used when.
- Communicating over a reliable network
- When some message loss is acceptable
- When message queuing wouldn’t be beneficial
Using QOS level 1
This method guarantees that the message will be delivered to the broker, but also doesn’t prevent it being received multiple times.
To achieve this the message is queued on the sender.
Use this level if your application must receive the message. However be very aware that message queuing can result in some undesirable outcomes as I cover in MQTT Client Message Queueing and Delivery.
QOS 2 Guaranteed Delivery no Duplicates
This is only used in exceptional cases and some brokers don’t even support this level.
The same considerations apply as for QOS level 1.
End to End QOS or Client to Client QOS
The QOS level is defined on the connection between client and broker.
The Quality of service between two clients connected to a broker is determined by the QOS of the published message,and the QOS of the subscribing client.
When a client subscribes to a broker with a QOS it is effectively instructing the broker to publish messages to it, with that QOS.
The overall QOS is always equal to the lowest QOS of the publish or subscribe, as shown in the table below
|QOS PUBLISH||QOS SUBSCRIBE||OVERALL QOS|
|0||0 or 1 or 2||0|
|1||1 or 2||1|
This means that you need to take into consideration the QOS of the published message when configuring the QOS level of the subscriber.
It doesn’t make sense subscribing with a QOS of 2 when the message was published with a QOS of 0 or 1.
However it may make sense to subscribe with a QOS of 1 even though the message was published with a QOS of 0 if for example the subscribing client was connected over an unreliable connection.
QOS Levels and Network Traffic
What many people forget is that the TCP employs error connection and each TCP/IP packet is acknowledged.
MQTT is an application level protocol and an application message can result in multiple TCP/IP packets
A QOS of 0 Results in 1 message at the application level message.
A QOS of 1 results in 2 application level messages.
A QOS of 2 results in 4 application level messages.
QOS, Message Delivery and Clients
Many people mistakenly assume that setting the QOS to 1 or 2 when publishing will mean a message will always be sent regardless of the state of the connection.
However this is not the case with the Python client or the node-red MQTT node and I assume other clients.
With Node-Red sending a message to a MQTT publish node when the node is disconnected will result in the message being silently dropped and not queued.
In order for the message to be sent the client will need some form of queue mechanism.
When Does the Client Queue Messages?
The client will generally accept and queue messages for transmission as long as it is connected to a broker.
QOS 0,1,2 messages will be sent so long as the client thinks it has a connection.
However QOS messages don’t get acknowledged and are dropped once sent. QOS 1,2 messages are held in a local queue until acknowledged.
Once the client sees the connection is lost it stops receiving new messages.
To help you choose the correct QOS for your project I will go through a few examples that I have made up. If you have any examples from your own implementations I would be happy to include them here just submit them on the comments.
Scenario 1– Group of sensors publishing temp,humidity and pressure to a local broker over a WI-FI and Ethernet TCP/IP network. The current network has plenty of spare capacity.
Data is being logged on the local network and missing readings are acceptable.
Solution– Using QOS of 0 is acceptable but 1 would be my choice
Scenario 2-A worker with an hand held device that scans products and sends product details back to a local broker to be logged in a database.
The worker must move around the warehouse that has some wi-fi black spots.
Solution- Using QOS of 1 would be my choice as the handheld could queue the data when in a blackspot and send it later when connected. However you would also need to implement some form of message queue on the client.
Related Resources and Tutorials
Hi Steve! Thanks for all the great articles!
I have a query regarding the line “However it may make sense to subscribe with a QOS of 1 even though the message was published with a QOS of 0 if for example the subscribing client was connected over an unreliable connection”.
This blog (https://blog.famzah.net/2022/10/03/mqtt-qos-level-between-publisher-and-subscribers/) and MQTT v3.1.1 (Section 3.8.4) seem to indicate that its impossible to upgrade QoS level, meaning that even if a subscriber requests a QoS of 1, the data is published as QoS 0.
Am I missing something?
Sorry but it is a bit misleading and I will rewrite it.
However generally messages are downgraded not upgraded . however subscribing with a qos of 1 means that it will receive qos 1 messages even if it disconnects and reconnects.
The subscribe is more important as the subscriber often has no idea of who is going to publish and with what qos level.
So Generally it is probably better to subscribe with a qos of 1.
Additionally there is a non standard setting is mosquitto that will queue qos 0 messages so they are effectively treated as qos 1 messages.
Here is the except from the manual
queue_qos0_messages [ true | false ]
Set to true to queue messages with QoS 0 when a persistent client is disconnected. When bridges topics are configured with QoS level 1 or 2 incoming QoS 0 messages for these topics are also queued. These messages are included in the limit imposed by max_queued_messages. Defaults to false.
Note that the MQTT v3.1.1 spec states that only QoS 1 and 2 messages should be saved in this situation so this is a non-standard option.
This option applies globally.
Reloaded on reload signal.
I did test it and it works as expected.