MQTT QoS (Quality of Service) ist die Zustellgarantie, die ein Client beim Veröffentlichen oder Abonnieren anfordert. In diesem Leitfaden sehen Sie genau, welche Pakete bei QoS 0, 1 und 2 ausgetauscht werden, warum die QoS beim Subscriber niedriger sein kann als die, mit der Sie veröffentlicht haben, wie Sessions Nachrichten für Offline-Clients zwischenspeichern und wie Sie all das in Python gegen broker.connectmq.com testen.
Wenn MQTT selbst neu für Sie ist, beginnen Sie mit Was ist ein MQTT-Broker? und kehren Sie dann hierher zurück.
Was MQTT QoS tatsächlich garantiert
MQTT läuft über TCP, sodass innerhalb einer Verbindung keine Bytes verloren gehen oder vertauscht werden. Bei QoS geht es um etwas anderes: was passiert, wenn eine Verbindung mitten in einer Zustellung abbricht, und ob der Empfänger dieselbe Nachricht möglicherweise doppelt erhält.
Zwei Punkte werden oft missverstanden:
- QoS gilt pro Teilstrecke, nicht Ende-zu-Ende. Die QoS des Publishers regelt die Strecke vom Publisher zum Broker. Die Abonnement-QoS regelt die Strecke vom Broker zum Subscriber. Der Broker ist für beide der Vermittler.
- Eine höhere QoS ist nicht automatisch „besser“. Jede Stufe bringt zusätzliche Pakete, Zustand und Latenz mit sich. Die richtige Wahl hängt davon ab, was Sie eine verlorene oder doppelte Nachricht kostet.
| Stufe | Name | Garantie | Pakete pro Nachricht (eine Strecke) | Duplikate möglich? |
|---|---|---|---|---|
| QoS 0 | At most once | Best Effort, keine Bestätigung | 1 | Nein, aber Verlust möglich |
| QoS 1 | At least once | Zugestellt, kann wiederholt werden | 2 | Ja |
| QoS 2 | Exactly once | Genau einmal zugestellt, keine Duplikate | 4 | Nein |
QoS 0: At Most Once
QoS 0 ist Fire and Forget. Der Sender schreibt ein PUBLISH-Paket in den Socket und vergisst es sofort. Es gibt keine Packet Identifier und keine Bestätigung.
Publisher Broker
| |
|------ PUBLISH (QoS 0) ---->|
| | (no reply, nothing stored)
Bricht die TCP-Verbindung ab, während das Paket noch in einem Puffer des Betriebssystems liegt, ist die Nachricht weg – und niemand merkt es. Das klingt schlimm, doch bei einem Temperaturwert, der alle zwei Sekunden gesendet wird, ersetzt der nächste Wert den verlorenen ohnehin. QoS 0 bietet die geringste Latenz und den kleinsten Overhead auf ressourcenarmen Geräten.
QoS 1: At Least Once
Bei QoS 1 vergibt der Sender einen Packet Identifier und hält die Nachricht vor, bis der Empfänger mit einem PUBACK mit derselben Kennung antwortet.
Publisher Broker
| |
|-- PUBLISH (QoS 1, id=7) -->| broker stores and forwards
|<------- PUBACK (id=7) -----|
| | publisher deletes message 7
Kommt das PUBACK nie an (zum Beispiel weil die Verbindung abbricht), sendet der Sender das PUBLISH nach dem Wiederverbinden mit gesetztem DUP-Flag erneut. Der Haken: Der Empfänger hat die erste Kopie möglicherweise schon verarbeitet und sieht die Nachricht dann zweimal. Deshalb bedeutet QoS 1 mindestens einmal.
QoS 1 ist das Arbeitspferd der meisten IoT-Systeme. Machen Sie Ihre Consumer idempotent (fügen Sie etwa eine Nachrichten-ID oder einen Zeitstempel in die Payload ein und ignorieren Sie Wiederholungen), dann reicht QoS 1 in der Regel völlig aus.
QoS 2: Exactly Once
QoS 2 nutzt einen vierstufigen Handshake, damit sich beide Seiten einig sind, dass die Nachricht genau einmal zugestellt wurde.
Publisher Broker
| |
|--- PUBLISH (QoS 2, id=9) --->| broker stores id 9, does not forward twice
|<------- PUBREC (id=9) -------| "received"
|-------- PUBREL (id=9) ------>| "release it, I will not resend"
|<------- PUBCOMP (id=9) ------| "complete", both sides drop id 9
Was die einzelnen Schritte bewirken:
- PUBLISH: Der Sender speichert die Nachricht und sendet sie mit einem Packet Identifier.
- PUBREC: Der Empfänger merkt sich die Kennung. Trifft ein doppeltes PUBLISH mit derselben ID ein, wird es erkannt und nicht erneut zugestellt.
- PUBREL: Der Sender verwirft die Nachricht und merkt sich ab jetzt nur noch die Kennung.
- PUBCOMP: Der Empfänger vergisst die Kennung. Der Austausch ist abgeschlossen.
Der Preis sind zwei Roundtrips pro Nachricht und Zustand auf beiden Seiten, bis der Ablauf abgeschlossen ist. Setzen Sie QoS 2 ein, wenn ein Duplikat echten Schaden anrichten würde und Sie den Consumer nicht idempotent gestalten können – etwa bei einem Befehl, der einen Zähler erhöht oder einen Abrechnungsvorgang auslöst.
MQTT-QoS-Downgrade: Warum Sie nicht immer die angeforderte QoS erhalten
Die QoS, die ein Subscriber erhält, ist nicht einfach die QoS, die der Publisher verwendet hat. Drei Werte spielen zusammen.
Effektive QoS = min(Publish-QoS, Abonnement-QoS)
Wenn der Broker eine Nachricht weiterleitet, verwendet er den niedrigeren Wert aus der QoS im ursprünglichen PUBLISH und der für das Abonnement gewährten QoS.
| Publisher-QoS | Abonnement-QoS | Zugestellt an Subscriber |
|---|---|---|
| 0 | 2 | 0 |
| 1 | 2 | 1 |
| 2 | 1 | 1 |
| 2 | 0 | 0 |
| 2 | 2 | 2 |
Wenn Sie also Ende-zu-Ende eine Exactly-once-Zustellung brauchen, müssen sowohl der Publisher als auch jeder Subscriber QoS 2 verwenden. Ein einziges Abonnement mit QoS 0 macht den Datenstrom dieses Subscribers stillschweigend zu Best Effort.
Die Maximum QoS des Brokers (MQTT 5)
In MQTT 5 kann der Broker in seinem CONNACK-Paket eine Maximum QoS ankündigen. Fehlt diese Property, darf der Client davon ausgehen, dass QoS 2 unterstützt wird. Ist sie vorhanden, darf der Client nicht oberhalb dieser Stufe veröffentlichen, und der Broker gewährt Abonnements höchstens auf dieser Stufe (das SUBACK teilt Ihnen die gewährte QoS mit).
Bei ConnectMQ hängt das davon ab, wohin Sie sich verbinden:
| Umgebung | Maximum QoS |
|---|---|
| Öffentlicher MQTT-Broker (broker.connectmq.com) | QoS 2 |
| Plan Serverless (Free) | QoS 1 |
| Plan Serverless (Paid) | QoS 2 |
| Dedicated, BYOC, Self Managed Enterprise | QoS 2 |
Prüfen Sie die gewährte QoS immer im SUBACK, statt sie vorauszusetzen. Die meisten Client-Bibliotheken stellen sie im Subscribe-Callback bereit. Die genauen Regeln beschreibt die MQTT-5-Spezifikation unter docs.oasis-open.org. Einen Überblick über weitere CONNACK-Properties finden Sie in Funktionen von MQTT 5.
Sessions, Session Expiry und Offline-Queuing
QoS schützt Nachrichten über einen Verbindungsabbruch hinweg nur, wenn die Session den Abbruch übersteht. Die Session ist der Zustand, den der Broker für einen Client vorhält: seine Abonnements, laufende QoS-1/2-Nachrichten und Nachrichten, die während seiner Offline-Zeit aufgelaufen sind.
- MQTT 3.1.1 nutzt das Flag Clean Session.
cleanSession=trueverwirft die Session beim Trennen.cleanSession=falsebittet den Broker, sie zu behalten. - MQTT 5 teilt dies in Clean Start (beim Verbinden neu beginnen oder nicht) und Session Expiry Interval (wie viele Sekunden die Session nach dem Trennen weiterlebt).
Solange eine persistente Session besteht und der Client offline ist, stellt der Broker QoS-1- und QoS-2-Nachrichten, die zu seinen Abonnements passen, in eine Warteschlange. QoS-0-Nachrichten werden für Offline-Clients nicht zwischengespeichert. Verbindet sich der Client mit derselben Client ID und ohne Clean Start erneut, werden die aufgelaufenen Nachrichten zugestellt.
Subscriber (id=sensor-reader) Broker
|-- CONNECT clean_start=0, expiry=600 -->|
|-- SUBSCRIBE plant/# QoS 1 ------------>|
| ... connection lost ... |
| | PUBLISH plant/a QoS 1 -> queued
| | PUBLISH plant/b QoS 0 -> dropped
|-- CONNECT clean_start=0 --------------->|
|<-- CONNACK session_present=1 -----------|
|<-- PUBLISH plant/a ---------------------|
Bei ConnectMQ ist Session Expiry pro Plan begrenzt, und auf dem öffentlichen MQTT-Broker leben Sessions bis zu 30 Minuten. Beachten Sie außerdem, dass Sessions im Arbeitsspeicher gehalten werden: Einen Neustart des Brokers überstehen sie nicht. Gestalten Sie kritische Abläufe daher so, dass sie ein Wiederverbinden mit session_present=0 verkraften.
Die richtige MQTT-QoS-Stufe wählen
| Anwendungsfall | Empfohlene QoS | Warum |
|---|---|---|
| Hochfrequente Telemetrie (Temperatur, Vibration, zyklische Maschinendaten) | 0 | Der nächste Messwert ersetzt einen verlorenen; geringster Overhead |
| Gerätestatus, Alarme, Ereignisse (etwa Störmeldungen einer SPS) | 1 | Muss ankommen; Duplikate lassen sich leicht ignorieren |
| Befehle an Aktoren (idempotent: „Ventil auf 40 % stellen“) | 1 | Denselben Befehl zu wiederholen, ist harmlos |
| Nicht idempotente Befehle („Zähler erhöhen“, „ausgeben“) | 2 | Ein Duplikat würde das Ergebnis verändern |
| Abrechnungs-, Mess- oder Transaktionsereignisse | 2 (oder 1 mit Dedup-IDs) | Exactly-once-Abrechnung |
Eine praktische Faustregel: Standardmäßig QoS 1 mit idempotenten Consumern, QoS 0 für hochfrequente Daten, deren Verlust verkraftbar ist, und QoS 2 nur für die wenigen Nachrichtentypen, bei denen ein Duplikat ein Fehler wäre.
In einem Unified Namespace (UNS), dessen Topics der ISA-95-Hierarchie (Enterprise → Site → Area → Line → Cell) folgen, legen Sie die QoS am besten pro Datenklasse fest: zyklische Messwerte wie acme/werk-stuttgart/montage/linie-1/zelle-3/temperatur mit QoS 0, Maschinenzustände und Störmeldungen derselben Zelle mit QoS 1. So wissen MES, Historian und Dashboards, welche Garantie sie auf welchem Zweig erwarten können.
Praxis: MQTT QoS 1 und QoS 2 in Python
Das folgende Skript verwendet paho-mqtt 2.x und den öffentlichen MQTT-Broker broker.connectmq.com (ohne Benutzername und Passwort). Es abonniert mit QoS 2, veröffentlicht eine Nachricht mit QoS 1 und eine mit QoS 2 und protokolliert die Bestätigungen. Installieren Sie die Bibliothek mit pip install "paho-mqtt>=2.0".
import time
import uuid
import paho.mqtt.client as mqtt
BROKER = "broker.connectmq.com"
UID = uuid.uuid4().hex[:8]
TOPIC = f"connectmq/demo/{UID}/qos"
def on_connect(client, userdata, flags, reason_code, properties):
print("CONNACK:", reason_code)
if properties is not None and hasattr(properties, "MaximumQoS"):
print("Broker Maximum QoS:", properties.MaximumQoS)
client.subscribe(f"{TOPIC}/#", qos=2)
def on_subscribe(client, userdata, mid, reason_code_list, properties):
print("SUBACK granted:", [rc.value for rc in reason_code_list])
def on_message(client, userdata, msg):
print(f"Received {msg.topic} QoS={msg.qos} payload={msg.payload.decode()}")
def on_publish(client, userdata, mid, reason_code, properties):
print(f"Publish flow complete for mid={mid}")
client = mqtt.Client(
mqtt.CallbackAPIVersion.VERSION2,
client_id=f"qos-demo-{UID}",
protocol=mqtt.MQTTv5,
)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_message = on_message
client.on_publish = on_publish
client.connect(BROKER, 1883, keepalive=30)
client.loop_start()
time.sleep(2)
client.publish(f"{TOPIC}/one", "hello at least once", qos=1).wait_for_publish()
client.publish(f"{TOPIC}/two", "hello exactly once", qos=2).wait_for_publish()
time.sleep(2)
client.loop_stop()
client.disconnect()
Bei QoS 1 wird on_publish ausgelöst, sobald das PUBACK eintrifft. Bei QoS 2 erst nach dem PUBCOMP, also am Ende des vierstufigen Handshakes. Wird keine Zeile zur Maximum QoS ausgegeben, hat der Broker die Property nicht gesendet – QoS 2 ist dann erlaubt.
Pakete mit der Mosquitto-CLI beobachten
Die Kommandozeilen-Tools von Eclipse Mosquitto geben mit -d jedes Paket aus und machen die oben beschriebenen Abläufe sichtbar. In einem Terminal:
mosquitto_sub -h broker.connectmq.com -p 1883 -i qos-sub-a1b2 -t "connectmq/demo/a1b2/#" -q 2 -v -d
Veröffentlichen Sie in einem zweiten Terminal mit QoS 1 und danach mit QoS 2:
mosquitto_pub -h broker.connectmq.com -p 1883 -i qos-pub-a1b2 -t "connectmq/demo/a1b2/q1" -q 1 -m "hello1" -d
mosquitto_pub -h broker.connectmq.com -p 1883 -i qos-pub-a1b2 -t "connectmq/demo/a1b2/q2" -q 2 -m "hello2" -d
Die Ausgabe des Publishers zeigt genau die zuvor beschriebenen Abfolgen:
Client qos-pub-a1b2 sending PUBLISH (d0, q1, r0, m1, 'connectmq/demo/a1b2/q1', ... (6 bytes))
Client qos-pub-a1b2 received PUBACK (Mid: 1, RC:0)
...
Client qos-pub-a1b2 sending PUBLISH (d0, q2, r0, m1, 'connectmq/demo/a1b2/q2', ... (6 bytes))
Client qos-pub-a1b2 received PUBREC (Mid: 1)
Client qos-pub-a1b2 sending PUBREL (m1)
Client qos-pub-a1b2 received PUBCOMP (Mid: 1, RC:0)
Ersetzen Sie a1b2 durch eine eigene Zufallszeichenfolge. Alles auf dem öffentlichen MQTT-Broker ist für jeden lesbar; er ist für Tests gedacht, veröffentlichen Sie dort also niemals vertrauliche Daten. Um mit Downgrades zu experimentieren, abonnieren Sie mit -q 0 und veröffentlichen mit -q 2: Die Debug-Ausgabe des Subscribers zeigt dann q0 beim zugestellten PUBLISH. Weitere Tipps zum öffentlichen Broker finden Sie unter Kostenloser öffentlicher MQTT-Broker.
Häufige QoS-Fehler
- Ende-zu-Ende QoS 2 annehmen, während ein Subscriber QoS 0 nutzt. Das schwächste Glied gewinnt.
- QoS 2 für hochfrequente Telemetrie verwenden. Vier Pakete pro Nachricht und Strecke summieren sich schnell, und das In-flight-Fenster (Receive Maximum) läuft voll.
- Zufällige Client IDs mit persistenten Sessions. Offline-Queuing funktioniert nur, wenn sich der Client mit derselben Client ID wieder verbindet. Eine neue Zufalls-ID erzeugt eine neue, leere Session.
- Die gewährte QoS im SUBACK ignorieren. In einem auf QoS 1 begrenzten Plan wird ein QoS-2-Abonnement als QoS 1 gewährt.
Starten Sie mit ConnectMQ
Der öffentliche MQTT-Broker eignet sich hervorragend, um MQTT QoS kennenzulernen, doch Produktivverkehr gehört auf einen privaten Broker mit Zugangsdaten. Registrieren Sie sich kostenlos unter app.connectmq.com (Serverless-Plan, ohne Kreditkarte), legen Sie einen Broker an und verwenden Sie den generierten Benutzernamen, das Passwort und die Client ID. Wechseln Sie zu Serverless (Paid) oder Dedicated, wenn Sie QoS 2, mehr Verbindungen oder größere Nachrichten benötigen.
Häufig gestellte Fragen
Was ist die Standard-QoS-Stufe in MQTT?
Die meisten Client-Bibliotheken verwenden standardmäßig QoS 0 für Publish und Subscribe. Setzen Sie die QoS in Ihrem Code explizit, damit das Verhalten für jeden Leser klar ist.
Macht QoS 2 MQTT langsamer?
Ja. QoS 2 benötigt pro Nachricht und Strecke vier Pakete und zwei Roundtrips, verglichen mit zwei Paketen bei QoS 1 und einem bei QoS 0. Für die meiste Telemetrie bieten QoS 0 oder 1 einen höheren Durchsatz.
Warum hat mein Subscriber QoS 1 erhalten, obwohl ich mit QoS 2 veröffentlicht habe?
Die zugestellte QoS ist das Minimum aus Publish-QoS und gewährter Abonnement-QoS. Ihr Abonnement wurde mit QoS 1 gewährt – entweder, weil Sie es so angefordert haben, oder weil die Maximum QoS des Brokers 1 ist, wie im ConnectMQ-Plan Serverless (Free).
Werden QoS-0-Nachrichten für Offline-Clients zwischengespeichert?
Nein. Broker speichern nur QoS-1- und QoS-2-Nachrichten für Clients mit persistenter Session zwischen. QoS-0-Nachrichten an einen Offline-Client werden verworfen.
Kann ich QoS 2 auf broker.connectmq.com verwenden?
Ja. Der öffentliche MQTT-Broker mit anonymem Zugang unterstützt QoS 0, 1 und 2. Private Broker unterstützen QoS 2 ab dem Plan Serverless (Paid), während der kostenlose Serverless-Plan auf QoS 1 begrenzt ist.



