MQTT-Grundlagen

MQTT Persistent Session und das Clean-Session-Flag erklärt

Mit einer Persistent Session merkt sich der Broker die Subscriptions eines Clients und puffert seine QoS-1- und QoS-2-Nachrichten, während er offline ist. Erfahren Sie, was gespeichert wird, wann sie sinnvoll ist und welche Fallstricke Sie vermeiden sollten.

Diagramm einer MQTT Persistent Session, bei der ein Broker Subscriptions und gepufferte Nachrichten für ein getrenntes IoT-Gerät vorhält
Probieren Sie es auf Ihrem eigenen MQTT-Broker ausHolen Sie sich im Free-Tarif einen privaten, verwalteten MQTT-Broker und starten Sie mit fertigen Codebeispielen.
Kostenlos testen Codebeispiele Keine Kreditkarte erforderlich

Mit einer MQTT Persistent Session merkt sich der Broker, wer ein Client ist, welche Topics er abonniert hat und welche Nachrichten er ihm noch schuldet, und zwar auch dann, wenn der Client gerade nicht verbunden ist. Nach diesem Artikel wissen Sie genau, was der Broker speichert, wie das Clean-Session-Flag (und sein Nachfolger in MQTT 5) das steuert und wie Sie das Verhalten mit wenigen Befehlen selbst überprüfen.

Was ist eine MQTT Persistent Session?

Jede MQTT-Verbindung hat eine Session: ein Bündel an Zustand, den sich Client und MQTT-Broker teilen. Bei einer Clean Session (nicht persistent) existiert dieser Zustand nur so lange wie die Netzwerkverbindung. Trennt sich der Client, verwirft der Broker alles. Bei einer Persistent Session behält der Broker den Zustand nach dem Verbindungsende und übergibt ihn wieder, sobald sich derselbe Client erneut verbindet.

Die Identität, die die alte Session mit der neuen Verbindung verknüpft, ist die Client-ID. Deshalb funktionieren Persistent Sessions nur, wenn sich ein Client jedes Mal mit exakt derselben ID verbindet.

Was der Broker speichert

Session-Zustand auf dem Broker Bei Persistent Session gespeichert?
Die Subscriptions des Clients (Topic-Filter und QoS) Ja
QoS-1- und QoS-2-Nachrichten, die eintrafen, während der Client offline war Ja
Gesendete, aber noch nicht bestätigte QoS-1- und QoS-2-Nachrichten Ja
Vom Client empfangene, aber noch nicht vollständig abgeschlossene QoS-2-Nachrichten Ja
QoS-0-Nachrichten, die veröffentlicht wurden, während der Client offline war Nein (Broker dürfen sie optional puffern, die meisten tun es nicht)
Retained Messages Kein Session-Zustand; werden pro Topic für alle gespeichert

Der Client hält seine eigene Hälfte: QoS-1- und QoS-2-Nachrichten, die er gesendet hat, die aber noch nicht bestätigt sind, sowie empfangene, noch nicht abgeschlossene QoS-2-Nachrichten. Eine Client-Bibliothek, die das nur im Arbeitsspeicher hält, verliert ihre Hälfte beim Neustart, was häufig für Verwirrung sorgt.

Was sie nicht leistet

Eine Persistent Session ist keine Datenbank. Sie speichert keinen Verlauf, spielt keine Nachrichten erneut ab, die der Client bereits bestätigt hat, und stellt QoS-0-Verkehr nicht zuverlässig zu. Außerdem puffert sie nur Nachrichten für Topics, die der Client bereits abonniert hatte, bevor er offline ging. Wenn Sie unabhängig von Sessions den „letzten Wert“ eines Topics benötigen, verwenden Sie stattdessen Retained Messages.

Das Clean-Session-Flag in MQTT 3.1.1

In MQTT 3.1.1 steuert ein einziges Bit im CONNECT-Paket alles:

  • cleanSession = true: eine bestehende Session verwerfen, neu beginnen und diese Session beim Trennen des Clients wieder verwerfen.
  • cleanSession = false: die bestehende Session für diese Client-ID fortsetzen, falls vorhanden, andernfalls eine neue anlegen und sie nach dem Trennen behalten.

Was passiert ist, teilt der Broker dem Client über das Session-Present-Flag im CONNACK mit. Haben Sie sich mit cleanSession = false verbunden und Session Present ist 0, hatte der Broker keinen Zustand für Sie gespeichert, und Sie müssen erneut abonnieren. Ist es 1, bestehen Ihre Subscriptions noch und gepufferte Nachrichten treffen gleich ein.

Die Schwäche von 3.1.1: Eine Persistent Session hat kein eingebautes Ablaufdatum. Ein außer Betrieb genommenes Gerät hinterlässt eine Session, die so lange Nachrichten sammelt, bis die Limits des Brokers greifen.

Persistent Sessions in MQTT 5

MQTT 5 teilt das Flag in zwei unabhängige Steuerungen auf:

  • Clean Start legt fest, ob beim Verbindungsaufbau eine bestehende Session verworfen wird.
  • Session Expiry Interval legt fest, wie viele Sekunden die Session nach dem Trennen weiterlebt.

Eine Persistent Session in MQTT 5 ist also Clean Start = false plus ein Session Expiry Interval größer als null. Die vollständige Zuordnung und die Wahl passender Werte behandelt der Artikel MQTT 5 Clean Start und Session Expiry Interval. Broker dürfen den angefragten Ablaufwert begrenzen; auf dem öffentlichen MQTT-Broker unter broker.connectmq.com beträgt das Maximum 30 Minuten.

MQTT Persistent Session Schritt für Schritt ausprobieren

Dieses Experiment nutzt den öffentlichen MQTT-Broker, der für Tests und Prototypen gedacht ist, nicht für Produktionsdaten. Wählen Sie statt p9k2 ein eigenes zufälliges Suffix, damit Sie nicht mit anderen Lesern kollidieren, und senden Sie keine sensiblen Daten, da dort alle Topics für jeden lesbar sind.

  1. Starten Sie einen Subscriber mit fester ID, Persistent Session und QoS 1:
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
  -i persist-demo-p9k2 -c -x 1800 -q 1 -v \
  -t 'connectmq/demo/p9k2/alerts'

-c deaktiviert Clean Start und -x 1800 fordert einen Session-Ablauf von 30 Minuten an.

  1. Beenden Sie den Subscriber mit Strg+C.

  2. Veröffentlichen Sie drei QoS-1-Nachrichten, während er offline ist:

for i in 1 2 3; do
  mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-p9k2 \
    -q 1 -t 'connectmq/demo/p9k2/alerts' -m "alert $i"
done
  1. Führen Sie exakt denselben Subscriber-Befehl erneut aus. Die drei Nachrichten treffen sofort ein, weil der Broker sie in Ihrer Session gepuffert hat.

  2. Wiederholen Sie den Test ohne -c. Diesmal kommt beim erneuten Verbinden nichts an: Die Session wurde bereinigt.

Derselbe Test in Python

import paho.mqtt.client as mqtt
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes

TOPIC = "connectmq/demo/p9k2/alerts"

def on_connect(client, userdata, flags, reason_code, properties):
    print("Connected:", reason_code, "session present:", flags.session_present)
    if not flags.session_present:
        # Der Broker hat keine Session für uns: erneut abonnieren
        client.subscribe(TOPIC, qos=1)

def on_message(client, userdata, msg):
    print(msg.topic, msg.payload.decode())

client = mqtt.Client(
    mqtt.CallbackAPIVersion.VERSION2,
    client_id="persist-py-p9k2",
    protocol=mqtt.MQTTv5,
)
client.on_connect = on_connect
client.on_message = on_message

props = Properties(PacketTypes.CONNECT)
props.SessionExpiryInterval = 1800  # Sekunden

client.connect("broker.connectmq.com", 1883, keepalive=60,
               clean_start=False, properties=props)
client.loop_forever()

session_present vor dem Abonnieren zu prüfen ist das idiomatische Muster: Es vermeidet unnötige Neu-Subscriptions und reagiert korrekt, wenn die Session abgelaufen ist.

Wann sich eine Persistent Session lohnt

Setzen Sie eine ein, wenn eine verpasste Nachricht ins Gewicht fällt und der Client sich mit stabiler Identität neu verbindet:

  • Geräte, die Befehle empfangen (Ventil öffnen, Konfiguration aktualisieren) und kurzzeitig aus dem Netz fallen können, etwa ein Edge-Gateway an einer SPS in der Fertigungshalle, dessen WLAN- oder Mobilfunkverbindung zeitweise abreißt.
  • Backend-Consumer, die jedes QoS-1-Ereignis verarbeiten müssen, etwa Alarm-Handler oder ein MES-Dienst, der Störmeldungen unter acme/werk-stuttgart/montage/linie-1/# lückenlos erfassen muss.
  • Batteriegeräte, die aufwachen, sich verbinden, ausstehende Befehle abholen und wieder schlafen.

Bevorzugen Sie eine Clean Session, wenn:

  • der Client nur Live-Daten benötigt, etwa ein Dashboard, das aktuelle Werte aus Retained Topics anzeigt.
  • Client-IDs zufällig sind oder von mehreren Instanzen wiederverwendet werden, zum Beispiel bei automatisch skalierten Web-Workern.
  • Sie nur veröffentlichen und nie abonnieren; dann gibt es kaum Session-Zustand, der sich zu behalten lohnt.

Fallstricke und Fehlerbehebung

  1. Zufällige Client-IDs. Viele Bibliotheken erzeugen eine zufällige ID, wenn Sie das Feld leer lassen. Eine neue ID bedeutet jedes Mal eine neue Session, es wird also nie etwas fortgesetzt. Legen Sie eine feste ID fest; siehe Best Practices für die MQTT Client-ID.
  2. Abonnieren mit QoS 0. Der Broker puffert Nachrichten nur mit dem QoS, mit dem Sie abonniert haben. Eine QoS-0-Subscription erhält offline nichts, selbst wenn der Publisher QoS 1 verwendet hat.
  3. Veröffentlichen mit QoS 0. Für die Zustellung gilt der niedrigere Wert aus Publish- und Subscription-QoS. QoS-0-Publishes werden nicht gepuffert.
  4. Nachrichten von vor dem ersten Subscribe erwarten. Eine Session puffert nur Nachrichten für Subscriptions, die sie bereits hat.
  5. Nachrichtenflut beim Neuverbinden. Ein Gerät, das stundenlang offline war, kann eine Welle gepufferter Nachrichten erhalten. Dimensionieren Sie Ihre Puffer passend oder nutzen Sie die Message Expiry von MQTT 5, damit veraltete Befehle in der Warteschlange verfallen.
  6. Broker-Neustarts. Wie Sessions gespeichert werden, ist ein Implementierungsdetail des jeweiligen Brokers. Bei ConnectMQ werden Sessions im Arbeitsspeicher gehalten; sie überstehen also Client-Trennungen, aber keinen Broker-Neustart. Planen Sie das ein: Prüfen Sie Session Present, abonnieren Sie bei 0 erneut und verwenden Sie Retained Messages für Zustand, der immer verfügbar sein muss.
  7. Tarifgrenzen. Der ConnectMQ-Tarif Serverless (Free) unterstützt QoS bis 1, was für gepufferte Zustellung völlig ausreicht. QoS 2 ist in den kostenpflichtigen Tarifen verfügbar.

Was genau und wie viel gepuffert wird, lesen Sie unter wie MQTT Nachrichten für Offline-Clients puffert. Neu beim Protokoll? Das MQTT-Tutorial beginnt bei den Grundlagen.

Persistent Sessions mit ConnectMQ betreiben

ConnectMQ ist ein verwalteter MQTT-Broker mit Unterstützung für MQTT 3.1.1 und 5.0, sodass sowohl das Clean-Session-Flag als auch der Session-Ablauf von MQTT 5 sofort funktionieren. Jeder Broker erhält generierte Zugangsdaten, und Client-IDs sind an diese Zugangsdaten gebunden, was verhindert, dass Fremde die Session Ihres Geräts kapern. Registrieren Sie sich für den kostenlosen Serverless-Tarif ohne Kreditkarte, verbinden Sie sich mit YOUR_USERNAME, YOUR_PASSWORD und YOUR_CLIENT_ID und wiederholen Sie den obigen Test auf Ihrem eigenen privaten Broker.

Häufig gestellte Fragen

Speichert eine MQTT Persistent Session QoS-0-Nachrichten?

In der Regel nicht. Die Spezifikation schreibt nur das Puffern von QoS-1- und QoS-2-Nachrichten vor; QoS 0 zu speichern ist optional, und die meisten Broker verzichten darauf. Verwenden Sie QoS 1 für alles, was Sie nicht verlieren dürfen.

Warum erhalte ich nach dem Neuverbinden keine gepufferten Nachrichten?

Die häufigsten Ursachen sind eine geänderte Client-ID, eine Verbindung mit Clean Session bzw. Clean Start auf true, eine QoS-0-Subscription oder eine bereits abgelaufene Session. Prüfen Sie das Session-Present-Flag im CONNACK, um zu sehen, ob die Session fortgesetzt wurde.

Muss ich bei einer Persistent Session erneut abonnieren?

Nur wenn Session Present 0 ist. Setzt der Broker Ihre Session fort, existieren Ihre Subscriptions bereits und Sie können das Abonnieren überspringen.

Überstehen Persistent Sessions einen Broker-Neustart?

Das hängt vom Broker ab. ConnectMQ hält Sessions im Arbeitsspeicher; sie überstehen also Client-Trennungen, werden bei einem Neustart des Brokers aber gelöscht. Clients sollten Session Present = 0 sauber behandeln.

Verwandte Artikel

Wer hat MQTT erfunden? Die Geschichte von Ölpipelines bis zum IoT

MQTT wurde 1999 von Andy Stanford-Clark (IBM) und Arlen Nipper (Arcom) erfunden, um Ölpipelines per Satellit zu überwachen. Verfolgen Sie den Weg zu Open Source, OASIS, ISO und den heutigen verwalteten MQTT-Brokern in der Cloud.

8 Min. Lesezeit

Alle Artikel →

Ihr privater MQTT-Broker ist nur wenige Klicks entfernt

Konto anlegen, Broker-Zugangsdaten erhalten und das erste Gerät verbinden — ohne Server, die installiert, gepatcht oder skaliert werden müssen.