Documentation Index Fetch the complete documentation index at: https://mintlify.com/hivemq/hivemq-community-edition/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Quality of Service (QoS) in MQTT defines the guarantee of message delivery between clients and the broker. MQTT provides three QoS levels, each offering different trade-offs between reliability, bandwidth, and latency.
QoS is applied separately for publish (client → broker) and subscribe (broker → client) operations.
QoS Levels Explained
QoS 0: At Most Once
The message is delivered at most once , or not at all. No acknowledgment, no retries, no storage.
Characteristics:
Fastest, lowest overhead
No acknowledgment (fire-and-forget)
Messages may be lost if network fails
No message duplication
Use cases:
High-frequency sensor data where occasional loss is acceptable
Temperature readings, GPS coordinates
Ambient monitoring where latest value matters most
Python QoS 0
JavaScript QoS 0
Java QoS 0
import paho.mqtt.client as mqtt
client = mqtt.Client( "qos0_publisher" )
client.connect( "localhost" , 1883 )
# Publish with QoS 0 (default)
client.publish( "sensors/temperature" , "22.5" , qos = 0 )
print ( "Message sent (fire and forget)" )
client.disconnect()
QoS 1: At Least Once
The message is delivered at least once , guaranteed. May result in duplicates.
Characteristics:
Acknowledged delivery (PUBACK)
Broker stores message until acknowledged
Retries if acknowledgment not received
May deliver duplicates if PUBACK is lost
Use cases:
Important sensor readings
Device status updates
Command delivery where duplicates can be handled
Most general-purpose messaging
Python QoS 1
JavaScript QoS 1
Java QoS 1
import paho.mqtt.client as mqtt
import time
def on_publish ( client , userdata , mid ):
print ( f "Message { mid } acknowledged by broker" )
client = mqtt.Client( "qos1_publisher" )
client.on_publish = on_publish
client.connect( "localhost" , 1883 )
client.loop_start()
# Publish with QoS 1
result = client.publish( "devices/status" , "online" , qos = 1 )
result.wait_for_publish()
print ( f "Message published, awaiting PUBACK..." )
time.sleep( 1 )
client.loop_stop()
client.disconnect()
QoS 1 can deliver duplicates. Implement idempotent message handlers or use message IDs to detect duplicates.
QoS 2: Exactly Once
The message is delivered exactly once , guaranteed. No loss, no duplicates.
Characteristics:
Four-way handshake (PUBLISH, PUBREC, PUBREL, PUBCOMP)
Highest overhead, slowest delivery
Guaranteed exactly-once delivery
No duplicates, no loss
Use cases:
Financial transactions
Critical commands (unlock door, disable alarm)
Billing/metering data
Any scenario where duplicates or loss are unacceptable
Python QoS 2
JavaScript QoS 2
Java QoS 2
import paho.mqtt.client as mqtt
import time
def on_publish ( client , userdata , mid ):
print ( f "Message { mid } delivered exactly once" )
client = mqtt.Client( "qos2_publisher" )
client.on_publish = on_publish
client.connect( "localhost" , 1883 )
client.loop_start()
# Publish with QoS 2 - exactly once delivery
result = client.publish(
"transactions/payment" ,
'{"amount": 100, "currency": "USD"}' ,
qos = 2
)
result.wait_for_publish()
print ( "Transaction message delivered" )
time.sleep( 1 )
client.loop_stop()
client.disconnect()
QoS Comparison Table
Feature QoS 0 QoS 1 QoS 2 Delivery Guarantee At most once At least once Exactly once Acknowledgment None PUBACK PUBREC/PUBREL/PUBCOMP Retries No Yes Yes Can Lose Messages Yes No No Can Duplicate No Yes No Bandwidth Lowest Medium Highest Latency Lowest Medium Highest Storage Required None Broker & Client Broker & Client
Subscriber QoS
The effective QoS is the minimum of publisher and subscriber QoS levels.
Downgrade Example
QoS Matrix
# Publisher sends with QoS 2
publisher.publish( "sensors/data" , "value" , qos = 2 )
# Subscriber subscribes with QoS 1
subscriber.subscribe( "sensors/data" , qos = 1 )
# Effective QoS: 1 (at least once)
# Broker → Subscriber uses QoS 1
Publish QoS Subscribe QoS Effective QoS 0 0 0 0 1 0 0 2 0 1 0 0 1 1 1 1 2 1 2 0 0 2 1 1 2 2 2
Practical Examples
Smart Home Temperature Monitoring
Temperature Publisher
Temperature Subscriber
import paho.mqtt.client as mqtt
import time
import random
client = mqtt.Client( "temp_sensor" )
client.connect( "localhost" , 1883 )
client.loop_start()
try :
while True :
temp = 20 + random.uniform( - 2 , 2 )
# Use QoS 0 for frequent updates
client.publish(
"home/livingroom/temperature" ,
f " { temp :.2f} " ,
qos = 0
)
# Use QoS 1 for threshold alerts
if temp > 25 :
client.publish(
"home/alerts/high_temp" ,
f "Temperature alert: { temp :.2f} °C" ,
qos = 1
)
time.sleep( 10 )
except KeyboardInterrupt :
client.loop_stop()
client.disconnect()
Industrial Control System
import paho.mqtt.client as mqtt
import json
def send_critical_command ( client , machine_id , command ):
"""Send critical command with QoS 2"""
payload = json.dumps({
"machine_id" : machine_id,
"command" : command,
"timestamp" : time.time()
})
result = client.publish(
f "factory/machine/ { machine_id } /command" ,
payload,
qos = 2 , # Exactly once for critical commands
retain = False
)
result.wait_for_publish()
print ( f "Command ' { command } ' delivered to { machine_id } " )
def send_telemetry ( client , machine_id , data ):
"""Send telemetry with QoS 0"""
client.publish(
f "factory/machine/ { machine_id } /telemetry" ,
json.dumps(data),
qos = 0 # Fire-and-forget for high-frequency data
)
client = mqtt.Client( "factory_controller" )
client.connect( "localhost" , 1883 )
client.loop_start()
# High-frequency telemetry (QoS 0)
send_telemetry(client, "m001" , { "rpm" : 1500 , "temp" : 45 })
# Critical emergency stop (QoS 2)
send_critical_command(client, "m001" , "EMERGENCY_STOP" )
client.loop_stop()
client.disconnect()
Handling QoS in Subscriptions
Duplicate Detection (QoS 1)
import paho.mqtt.client as mqtt
# Track processed message IDs to detect duplicates
processed_messages = set ()
def on_message ( client , userdata , msg ):
# Create message fingerprint
msg_id = f " { msg.topic } : { msg.payload.decode() } "
if msg_id in processed_messages:
print ( f "Duplicate detected: { msg.topic } " )
return
processed_messages.add(msg_id)
print ( f "Processing: { msg.topic } = { msg.payload.decode() } " )
# Keep set size manageable
if len (processed_messages) > 1000 :
processed_messages.clear()
client = mqtt.Client( "dedup_subscriber" )
client.on_message = on_message
client.connect( "localhost" , 1883 )
client.subscribe( "sensors/#" , qos = 1 )
client.loop_forever()
Choosing the Right QoS:
Use QoS 0 when:
High message frequency (>1/second)
Latest value is most important
Network is reliable
Example: Live sensor readings
Use QoS 1 when:
Messages must arrive
Duplicates can be handled
Balance of reliability and performance needed
Example: Status updates, notifications
Use QoS 2 when:
Exactly-once delivery is critical
Duplicates would cause problems
Performance is secondary to correctness
Example: Financial data, critical commands
Bandwidth Impact
import time
import paho.mqtt.client as mqtt
def benchmark_qos ( qos_level , message_count = 100 ):
client = mqtt.Client( f "benchmark_qos { qos_level } " )
client.connect( "localhost" , 1883 )
client.loop_start()
start = time.time()
for i in range (message_count):
result = client.publish(
"benchmark/test" ,
f "message_ { i } " ,
qos = qos_level
)
if qos_level > 0 :
result.wait_for_publish()
elapsed = time.time() - start
client.loop_stop()
client.disconnect()
print ( f "QoS { qos_level } : { elapsed :.2f} s for { message_count } messages" )
print ( f "Average: { (elapsed / message_count) * 1000 :.2f} ms per message" )
for qos in [ 0 , 1 , 2 ]:
benchmark_qos(qos)
print ()
Common Pitfalls
Avoid These Mistakes:
Using QoS 2 everywhere : Unnecessary overhead for most use cases
Ignoring duplicates with QoS 1 : Can lead to incorrect state
Not waiting for publish acknowledgment : Messages may be lost on disconnect
Mismatching QoS expectations : Publisher QoS 2 doesn’t guarantee subscriber receives QoS 2
Testing QoS Behavior
# Terminal 1: Subscribe with different QoS levels
mosquitto_sub -h localhost -t "test/qos0" -q 0 -v
mosquitto_sub -h localhost -t "test/qos1" -q 1 -v
mosquitto_sub -h localhost -t "test/qos2" -q 2 -v
# Terminal 2: Publish with different QoS
mosquitto_pub -h localhost -t "test/qos0" -m "QoS 0 message" -q 0
mosquitto_pub -h localhost -t "test/qos1" -m "QoS 1 message" -q 1
mosquitto_pub -h localhost -t "test/qos2" -m "QoS 2 message" -q 2
# Test network interruption
# Stop subscriber, publish QoS 1/2 messages, restart subscriber
# QoS 0: Lost
# QoS 1/2: Delivered after reconnection (if clean_session=False)
Next Steps
Retained Messages Learn how retained messages work with QoS
Publishing & Subscribing Master the pub/sub pattern