Protokolle und Daten

MQTT QoS, Retain-Nachrichten und veraltete Daten

MQTT QoS 0, 1 und 2, Retain-Nachrichten, Sitzungen und Last Will: Was bestätigt wird und wie Sie veraltete Messwerte erkennen.

Ein Dashboard verbindet sich um 08:00 Uhr mit einem MQTT-Broker und zeigt für einen Zähler 42 kW an. Der Zähler hat am Vortag um 18:00 Uhr die Stromversorgung verloren. Der Broker hat dem Dashboard die letzte gespeicherte Retain-Nachricht des Zähler-Topics gesendet. Im MQTT-Paket stand nicht, dass der Wert 14 Stunden alt war.

Dieser Leitfaden erklärt, was die einzelnen MQTT-Zustelloptionen belegen: die drei QoS-Stufen, Retain-Nachrichten, persistente Sitzungen, Last Will und Nachrichtenablauf. Abschnittsnummern beziehen sich auf den OASIS-Standard MQTT 5.0. Unterschiede zu MQTT 3.1.1 werden ausdrücklich genannt.

Der Leitfaden gehört zur Reihe über OPC UA und MQTT. Sie beginnt mit dem Vergleich von OPC UA, MQTT und Modbus. TLS, Zertifikate und Topic-Berechtigungen behandelt der MQTTS-Leitfaden.

Die drei QoS-Stufen

QoS (Quality of Service) legt den Bestätigungsablauf je Übertragungsabschnitt fest. Abschnitt 4.3 des Standards definiert drei Stufen:

QoSBezeichnungPakete je Nachricht und AbschnittErgebnis auf diesem Abschnitt
0Höchstens einmalPUBLISHEinmal zugestellt oder verloren; keine Bestätigung
1Mindestens einmalPUBLISH, PUBACKZugestellt, kann aber mehrfach eintreffen
2Genau einmalPUBLISH, PUBREC, PUBREL, PUBCOMPEinmal zugestellt, ohne Duplikate auf diesem Abschnitt

QoS gilt je Übertragungsabschnitt

Eine Nachricht durchläuft zwei Abschnitte: vom Publisher zum Broker und vom Broker zu jedem Subscriber. QoS gilt für jeden getrennt. Der Broker stellt mit dem niedrigeren von zwei Werten zu: dem QoS der PUBLISH-Nachricht und dem maximal gewährten QoS des Abonnements. Ein mit QoS 2 veröffentlichter Messwert kommt bei einem QoS-0-Abonnement mit QoS 0 an.

Ein PUBACK ist die Antwort auf ein QoS-1-PUBLISH auf einem Übertragungsabschnitt; sein Empfang allein belegt nicht grundsätzlich die Annahme. Es belegt weder den Empfang durch einen Subscriber noch die Speicherung durch eine Anwendung. Bei MQTT 5 enthält PUBACK einen Reason Code (Abschnitt 3.4.2.1). Sowohl 0x00 „Success“ als auch 0x10 „No matching subscribers“ bedeuten Annahme. Ein Broker kann 0x10 senden, wenn ihm kein Abonnent des Topics bekannt ist, muss dies aber nicht. Daher belegt 0x00 nicht, dass überhaupt ein Subscriber existiert. Codes ab 0x80 lehnen die Nachricht ab, zum Beispiel 0x87 „Not authorized“ und 0x97 „Quota exceeded“. Ein Publisher, der jedes PUBACK als Erfolg zählt, verliert diese Messwerte ohne Fehlermeldung.

MQTT 3.1.1 kennt keine Reason Codes. Ein Broker, der ein PUBLISH zurückweist, muss es entweder normal bestätigen oder die Verbindung schließen (Abschnitt 3.3.5 von 3.1.1). Eine bestätigte Veröffentlichung kann also trotzdem zurückgewiesen worden sein.

QoS für Telemetrie auswählen

DatenÜbliche Wahl
Häufige Messwerte, bei denen ein verlorener Einzelwert nicht kritisch istQoS 0
Energiewerte, Zählerstände und Ereignisse, die ankommen müssenQoS 1; Duplikate beim Empfänger entfernen
Befehle und einmalige TransaktionenQoS 1 oder 2, Befehlsablaufzeit und Bestätigung auf Anwendungsebene

QoS 1 ist für Energiedaten üblich. Je Abschnitt benötigt es zwei Pakete pro Nachricht, QoS 2 vier. Manche Dienste bieten QoS 2 nicht an: AWS IoT Core unterstützt nur QoS 0 und 1.

Geben Sie jedem Befehl neben dem QoS ein Gültigkeitsende. Ein während eines Ausfalls in der Warteschlange stehender Befehl wird nach Wiederverbindung übertragen. Ein MQTT-5-Message-Expiry-Interval (Abschnitt 3.3.2.3.3) oder ein Gültig-bis-Zeitpunkt im Payload verhindert, dass der Sollwert vom Vorabend erst am nächsten Morgen die Anlage erreicht.

Duplikate

Bei QoS 1 sendet der Absender jedes noch nicht bestätigte PUBLISH erneut, wenn die Verbindung abbricht (Abschnitt 4.4). Hat der Empfänger die erste Kopie bereits verarbeitet, erhält er den Messwert zweimal.

Die Protokollfelder bilden keinen stabilen Schlüssel, um Duplikate über beide Übertragungsabschnitte zu erkennen. Der Broker setzt das DUP-Flag für eigene Wiederholungen auf dem ausgehenden Abschnitt; er übernimmt das empfangene DUP-Flag nicht (Abschnitt 3.3.1.1). Die Paketkennung gilt nur auf einem Abschnitt. Nach Eintreffen des PUBACK darf der Absender sie erneut verwenden (Abschnitt 2.2.1).

Entfernen Sie Duplikate über einen Anwendungsschlüssel: Gerätekennung, Kanal und Messzeitstempel oder eine von der Quelle je Messung erhöhte Sequenznummer. Beispiel:

JSON
{"device":"meter-12","channel":"p_total","ts":"2026-09-23T14:05:00Z","seq":48213,"value":42.0,"unit":"kW"}

Ein Empfänger, der Messwerte unter einem eindeutigen Schlüssel aus Gerät, Kanal und ts speichert, verwirft die zweite Kopie. Schreiben Sie die Zeit in UTC, als Text nach RFC 3339 oder als Millisekunden seit der Unix-Epoche. Halten Sie die Uhr der Quelle per NTP synchron. Der Zeitstempel-Leitfaden erläutert Messzeit und Ankunftszeit.

Retain-Nachrichten

Ist das Retain-Flag bei PUBLISH gesetzt, speichert der Broker die Nachricht als letzten Wert dieses Topics (Abschnitt 3.3.1.3). Je Topic hält er eine Retain-Nachricht. Eine neue ersetzt die alte; eine Retain-Nachricht mit leerem Payload löscht sie. Wurde die Retain-Nachricht mit QoS 0 veröffentlicht, darf der Broker sie jederzeit verwerfen.

Der Broker sendet die gespeicherte Nachricht an jedes neue Abonnement eines passenden Topics, mit gesetztem Retain-Flag. Später eintreffende Nachrichten eines aktiven Publishers erreichen den Subscriber mit gelöschtem Retain-Flag. So kann ein Subscriber gespeicherte von aktuellen Nachrichten unterscheiden. Das Flag sagt aber nichts über das Alter des gespeicherten Werts. Bei MQTT 5 erhält ein Abonnement mit „Retain As Published = 1“ das Flag so, wie es der Publisher gesetzt hat. Bridges nutzen diese Option; ein Subscriber hinter einer Bridge kann sich deshalb nicht auf das Flag verlassen.

In MQTT 5 bestimmt der Subscriber außerdem, ob er Retain-Nachrichten überhaupt erhält (Abschnitt 3.8.3.1). „Retain Handling 0“ sendet sie bei jedem Subscribe, 1 nur bei einem neuen Abonnement und 2 nie. MQTT 3.1.1 hat diese Option nicht.

Speichern Sie per Retain Zustände, die ein neuer Subscriber sofort braucht, beispielsweise die Gerätekonfiguration oder den Online-Status. Retain-Telemetrie verursacht das Problem der Einleitung. Drei Maßnahmen begrenzen dieses Risiko:

  1. Schreiben Sie den Messzeitstempel in jeden Payload und lassen Sie ihn vom Subscriber prüfen. Kennzeichnen Sie einen Wert nach einer festen Zahl ausgebliebener Intervalle als veraltet. Bei einem Zähler mit Meldung jede Minute ergeben drei Intervalle drei Minuten.
  2. Setzen Sie ein MQTT-5-Message-Expiry-Interval entsprechend der Veraltungsgrenze, beispielsweise 180 s. Danach verwirft der Broker die Nachricht, auch wenn sie als Retain gespeichert ist. Der Broker verringert das Intervall zudem um die Wartezeit der Nachricht, sodass der Subscriber die verbleibende Zeit sieht. MQTT 3.1.1 kennt kein Message Expiry; dort schützt nur die Prüfung des Zeitstempels.
  3. Veröffentlichen Sie Messwerte ohne Retain-Flag und behalten Sie Retain nur für ein Status-Topic.

Sitzungen und Last Will

Eine persistente Sitzung erhält die Abonnements eines Clients, während er nicht verbunden ist. Der Broker stellt eingehende QoS-1- und QoS-2-Nachrichten für ihn in eine Warteschlange und sendet beim Verbindungsabbruch unbestätigte Nachrichten erneut. QoS-0-Nachrichten in die Warteschlange zu stellen ist laut Standard optional (Abschnitt 4.1).

Bei MQTT 5 verbindet sich der Client mit „Clean Start = 0“ und einem Session-Expiry-Interval größer als 0, beispielsweise 86.400 s für einen Tag. „Clean Start = 1“ verwirft die alte Sitzung. Ist das Session-Expiry-Interval 0 oder fehlt es, endet die Sitzung beim Schließen der Verbindung (Abschnitt 3.1.2.11.2). Bei MQTT 3.1.1 verbindet sich der Client mit „Clean Session = 0“; das Protokoll legt keine Sitzungsablaufzeit fest. In beiden Versionen zeigt das Session-Present-Flag im CONNACK an, ob der Broker die Sitzung noch hatte.

Die Warteschlange des Brokers ist begrenzt. Mosquitto hält je Client zusätzlich zu bereits laufenden Nachrichten bis zu 1.000 QoS-1- und QoS-2-Nachrichten (max_queued_messages) und verwirft darüber hinausgehende. Standardmäßig stellt es für einen getrennten Client keine QoS-0-Nachrichten in die Warteschlange (queue_qos0_messages false). Bei sechs empfangenen Messwerten pro Minute ist eine Warteschlange mit 1.000 Nachrichten in weniger als drei Stunden voll. Bemessen Sie sie nach Nachrichtenrate und längstem erwarteten Ausfall oder halten Sie die Historie beim Publisher.

Last Will ist eine Nachricht, die der Broker für einen Client veröffentlicht, wenn dessen Verbindung ohne normales DISCONNECT endet: nach Netzwerkausfall, ausgebliebener Keep-Alive-Nachricht oder geschlossenem Socket (Abschnitt 3.1.2.5). Ein Status-Topic verwendet sie so:

  1. Das Gateway verbindet sich mit einem Will „offline“ auf seinem Status-Topic und „Will Retain = 1“.
  2. Steht die Verbindung, veröffentlicht das Gateway „online“ auf demselben Topic mit Retain-Flag.
  3. Vor einer geplanten Abschaltung veröffentlicht das Gateway „offline“ mit Retain-Flag und trennt danach die Verbindung.

Ohne Will Retain sendet der Broker „offline“ nur an aktuell verbundene Subscriber. Das gespeicherte „online“ bleibt auf dem Topic. Ein später verbindendes Dashboard zeigt das Gateway dann fälschlich als online an. Schritt 3 ist nötig, weil ein DISCONNECT mit Reason Code 0x00 den Will löscht, ohne ihn zu veröffentlichen.

MQTT 5 ergänzt ein Will-Delay-Interval (Abschnitt 3.1.3.2.2). Verbindet sich der Client vor Ablauf erneut, veröffentlicht der Broker den Will nicht. Eine Verzögerung von 30 s verhindert, dass ein kurzer Netzausfall das Gateway als offline erscheinen lässt. Der Broker veröffentlicht den Will bei Ablauf der Verzögerung oder bei Ende der Sitzung, je nachdem, was zuerst eintritt. Mit Session-Expiry-Interval 0 endet die Sitzung beim Trennen; die Verzögerung wirkt dann nicht. MQTT 3.1.1 hat keine Will-Verzögerung.

Prüfliste für Aktualität

Dokumentieren Sie für jedes Telemetrie-Topic:

  • den QoS für Veröffentlichung und jedes Abonnement;
  • welche PUBACK-Reason-Codes der Publisher als Fehler behandelt;
  • ob und weshalb Nachrichten mit Retain gespeichert werden;
  • die Ablaufzeit der Nachricht, falls vorhanden;
  • wo der Messzeitstempel im Payload steht und welches Format er hat;
  • den Schlüssel, mit dem der Empfänger Duplikate entfernt;
  • Sitzungsablaufzeit und Warteschlangengrenze des Brokers;
  • Status-Topic und Last Will der Quelle mit gesetztem Will Retain;
  • ab welchem Alter Dashboard oder Berechnung einen Wert als veraltet behandeln.

Der Leitfaden zu veralteten Daten beschreibt die Kennzeichnung und Behandlung zu alter Messwerte.

MQTT mit Edge

Edge auf dem ZGW-20 Gateway sendet Messwerte an den MQTT-Broker einer Plattform, falls erforderlich über MQTTS. Edge veröffentlicht mit QoS 1. Eine Zustellung gilt erst mit Eintreffen des PUBACK vom Broker als abgeschlossen. Bei Verbindungsabbruch oder Veröffentlichungsfehler landen die Messwerte in einer lokalen Outbox auf dem Gateway. Standardmäßig versucht Edge die Zustellung bei erreichbarem Ziel jede Minute erneut. Ein erneut gesendeter Wert behält seinen ursprünglichen Messzeitstempel. Die Outbox hat keine Altersgrenze. Standardmäßig unterbricht eine Schutzschwelle für wenig freien Speicher neue Aufzeichnungen, wenn weniger als 10 % des Dateisystems frei sind, höchstens jedoch 1 GiB, oder wenn der freie Speicher unter 256 MiB fällt. Messwerte, die beim Stromausfall des Gateways noch im Arbeitsspeicher liegen, sind noch nicht in der Outbox und können verloren gehen. Der Leitfaden zu Store and Forward erklärt die Bemessung.

Ein PUBACK allein belegt nicht, dass die Plattform den Messwert angenommen oder gespeichert hat. Prüfen Sie bei MQTT 5 die Reason Codes; MQTT 3.1.1 kann eine verweigerte Veröffentlichungsberechtigung nicht im PUBACK melden. Eine erneute Zustellung nach Wiederverbindung kann einen Messwert doppelt liefern. Die Plattform muss Duplikate anhand von Gerät, Kanal und Zeitstempel entfernen. Suchen Sie bei der Inbetriebnahme einen bekannten Messwert im Speicher der Plattform und vergleichen Sie Zeitstempel und Wert mit Edge.

Häufige Fragen

Soll ich QoS 1 oder QoS 2 für Sensordaten verwenden?

Nutzen Sie QoS 1 und entfernen Sie Duplikate beim Empfänger anhand von Gerät, Kanal und Messzeitstempel. QoS 2 benötigt auf jedem Abschnitt vier Pakete je Nachricht und verhindert Duplikate nur dort. Manche Dienste bieten es nicht an: AWS IoT Core unterstützt QoS 0 und 1. Wenn ein Publisher nach einem Ausfall Messwerte erneut sendet, kann er weiterhin Duplikate erzeugen, die QoS 2 nicht erkennt.

Wie lösche ich eine Retain-Nachricht?

Veröffentlichen Sie auf demselben Topic eine Nachricht mit gesetztem Retain-Flag und leerem Payload. Der Broker entfernt die gespeicherte Nachricht und speichert die leere nicht. Aktuelle Subscriber empfangen trotzdem die leere Nachricht und müssen sie ignorieren, statt sie als Messwert zu parsen.

Warum zeigt ein Dashboard ein ausgefallenes Gerät noch als online an?

Häufig wurde der Will ohne Will Retain gesendet. Dann veröffentlicht der Broker „offline“ nur für aktuelle Subscriber, während das gespeicherte „online“ für spätere Subscriber auf dem Topic bleibt. Eine andere Ursache ist ein Will, der nie ausgelöst wird: Ein normales DISCONNECT löscht ihn. Vor einem geplanten Herunterfahren muss der Client deshalb selbst „offline“ veröffentlichen.