Wenn Ihr MQTT-Client ständig die Verbindung trennt, liegt die Ursache fast immer bei einem von fünf Punkten: zwei Clients teilen sich eine Client ID, ein Keep-Alive-Timeout, das Netzwerk verwirft inaktive Verbindungen stillschweigend, ein Paket, das der Broker nicht akzeptiert, oder ein Plan- bzw. Raten-Limit. Dieser Leitfaden erklärt, wie Sie jede Ursache an Symptomen und Logs erkennen, und führt Sie durch einen Diagnoseablauf, der Sie schnell zur Lösung bringt.
Beginnen Sie mit dem Trennungsmuster
Bevor Sie Einstellungen ändern, beobachten Sie, wie die Trennungen ablaufen. Der zeitliche Verlauf verrät viel:
| Muster | Wahrscheinlichste Ursache |
|---|---|
| Zwei Geräte trennen sich abwechselnd alle paar Sekunden | Doppelte Client ID |
| Trennung in regelmäßigem Abstand, etwa 1,5 x Keep Alive | Keep Alive wird nicht bedient |
| Trennung nach mehreren Minuten Inaktivität, nur in bestimmten Netzwerken | Idle-Timeout von NAT oder Firewall |
| Trennung direkt nach dem Publish einer bestimmten Nachricht | Paket zu groß oder ungültiges Topic |
| Trennung bei Verkehrsspitzen | Raten-Limit oder Kontingent |
| Trennung unmittelbar nach jedem Verbindungsaufbau | Autorisierungs- oder Subscription-Fehler |
Finden Sie außerdem heraus, welche Seite die Verbindung schließt. Bei MQTT 5 kommt ein vom Broker ausgelöstes Schließen mit einem DISCONNECT-Paket und einem Reason Code. Bei MQTT 3.1.1 schließt der Broker einfach den Socket. Stellen Sie den Client beim Debugging nach Möglichkeit auf MQTT 5 um; der Reason Code beantwortet die Frage oft sofort. Die Referenz der MQTT Reason Codes listet sie alle auf.
Ursache 1: Doppelte Client IDs
Die MQTT-Spezifikation schreibt vor: Verbindet sich ein Client mit einer Client ID, die bereits verbunden ist, muss der Broker den bestehenden Client trennen. Haben beide Clients automatische Reconnects aktiviert, werfen sie sich gegenseitig endlos hinaus. In MQTT 5 erhält der unterlegene Client den Reason Code 0x8E Session taken over.
Das passiert häufiger, als man denkt:
- Firmware mit fest codierter Client ID wurde auf mehrere Geräte geflasht.
- Ein Dienst wurde mit derselben Konfiguration auf zwei Replikate skaliert.
- Ein Entwickler führt dasselbe Skript in zwei Terminals aus.
- Ein Desktop-MQTT-Tool mit der ID Ihres Geräts ist noch geöffnet.
Lösung: Leiten Sie Client IDs von etwas Eindeutigem ab, etwa einer MAC-Adresse, Seriennummer oder einem Hostnamen, und teilen Sie eine ID nie zwischen Prozessen. Der Leitfaden zur MQTT Client ID behandelt Namensmuster. Bei verwalteten MQTT-Brokern, die Client IDs zusammen mit Zugangsdaten ausgeben, betreiben Sie genau eine Verbindung pro ausgegebener ID.
Ursache 2: Keep-Alive-Timeouts
Keep Alive ist ein Versprechen des Clients: „Du hörst mindestens alle N Sekunden von mir.“ Empfängt der Broker für das 1,5-Fache dieses Intervalls nichts, schließt er die Verbindung, in MQTT 5 mit dem Grund 0x8D Keep Alive timeout. Der Client sendet PINGREQ, wenn er nichts anderes zu senden hat, aber nur, wenn seine Netzwerkschleife läuft.
Typische Wege, das zu brechen:
- Eine lange blockierende Funktion wie
time.sleep(120)oder eine langsame HTTP-Anfrage im selben Thread aufrufen, in dem die MQTT-Schleife läuft. - Auf Arduino vergessen,
mqtt.loop()häufig aufzurufen, oder minutenlangdelay()verwenden. - Keep Alive auf einer Mobilfunkverbindung mit hoher Latenz sehr kurz einstellen, etwa auf 5 Sekunden.
- Deep-Sleep-Zyklen, die länger als das Keep-Alive-Intervall sind, ohne sauberes Trennen.
Lösung: Lassen Sie die Netzwerkschleife in einem Hintergrund-Thread laufen (loop_start() in Paho, MQTT.js erledigt das automatisch), halten Sie blockierende Arbeit von diesem Thread fern und wählen Sie für die meisten Einsätze einen Keep Alive von 30 bis 120 Sekunden. Der Leitfaden zum Keep-Alive-Intervall erklärt, wie Sie ihn abstimmen.
Ursache 3: Idle-Timeouts von NAT und Firewall
Mobilfunknetze, Heimrouter, Unternehmens-Firewalls und die Firewalls zwischen OT- und IT-Netz eines Werks verfolgen TCP-Verbindungen und verwerfen sie nach einer Zeit der Inaktivität stillschweigend. Weder Client noch Broker werden informiert. Der Client bemerkt das Problem erst beim nächsten Sendeversuch, der Broker erst, wenn der Keep Alive abläuft.
Das verräterische Zeichen: Die Trennungen treten im Mobilfunk, hinter dem LTE-Router einer Maschine oder an einem bestimmten Werk auf, aber nicht in Ihrem Entwicklungsnetz. Lösung: Setzen Sie den Keep Alive niedriger als den Idle-Timeout des Netzwerks, damit der PINGREQ-Verkehr die Zuordnung am Leben hält. Verwirft ein Provider inaktive Verbindungen nach einigen Minuten, sind 60 Sekunden Keep Alive ein vernünftiger Ausgangspunkt.
Ursache 4: Zu große oder ungültige Pakete
Broker schließen die Verbindung, wenn sie ein Paket empfangen, das sie nicht akzeptieren können. Typische Auslöser:
- Payload über der maximalen Nachrichtengröße des Brokers. MQTT-5-Clients sehen
0x95 Packet too large, 3.1.1-Clients verlieren einfach die Verbindung. Siehe den Leitfaden zur maximalen MQTT-Nachrichtengröße. - Publish auf ein Topic mit
+oder#. Wildcards sind nur in Subscriptions gültig. - Ungültiges UTF-8 in einem Topic-Namen, entstanden durch String-Verkettung mit Binärdaten.
- Fehlerhafte Nutzung von Topic Aliases nach einem Reconnect in MQTT 5.
Lösung: Protokollieren Sie vor jedem Publish das Topic und die Payload-Größe und prüfen Sie, ob die Trennung auf eine bestimmte Nachricht folgt. Dieselbe zu große Nachricht wird nach dem Reconnect oft erneut gesendet, wodurch eine Schleife entsteht.
Ursache 5: Raten-Limits und Kontingente
Geteilte Broker und verwaltete MQTT-Broker schützen sich mit Limits. Schnelleres Veröffentlichen als erlaubt, mehr Verbindungen als Ihr Plan zulässt oder eine überschrittene Anzahl an Subscriptions können zu Ablehnungen oder Trennungen führen. Achten Sie in MQTT 5 auf 0x96 Message rate too high und 0x97 Quota exceeded.
Auf dem Öffentlichen MQTT-Broker unter broker.connectmq.com, der für Tests und Prototypen gedacht ist, ist jeder Client auf 10 Nachrichten pro Sekunde, 10 Subscriptions und 64 KB pro Nachricht begrenzt. Private Broker haben stattdessen Limits pro Plan; der kostenlose Serverless-Plan erlaubt zum Beispiel bis zu 25 Verbindungen und Nachrichten bis 256 KB.
Ein Diagnoseablauf, der funktioniert
- Aktivieren Sie das Client-Logging. In Paho
client.enable_logger(), in den Mosquitto-Tools-d, in MQTT.js setzen SieDEBUG=mqttjs*. - Verbinden Sie sich per MQTT 5 und protokollieren Sie Reason Code und Reason String jedes DISCONNECT.
- Erfassen Sie die Zeitstempel von Verbindungsaufbau und Trennung und vergleichen Sie das Intervall mit Ihrem Keep Alive.
- Prüfen Sie die Broker-Seite. Sehen Sie sich den Verbindungsstatus der Client ID auf dem Broker an und prüfen Sie, ob im selben Moment eine weitere Verbindung mit derselben ID auftaucht.
- Reproduzieren Sie mit einem minimalen Client. Starten Sie
mosquitto_submit denselben Zugangsdaten im selben Netzwerk. Bleibt es verbunden, liegt das Problem in Ihrer Anwendung. - Ändern Sie immer nur eine Sache: Client ID, Keep Alive, Payload-Größe, Publish-Rate.
Hier ein minimaler Python-Client, der alles protokolliert, was Sie für die Schritte 1 bis 3 brauchen:
import time
import paho.mqtt.client as mqtt
started = time.time()
def ts():
return f"[{time.time() - started:7.1f}s]"
def on_connect(client, userdata, flags, reason_code, properties):
print(ts(), "CONNECT", reason_code, "session_present:", flags.session_present)
client.subscribe("connectmq/demo/5a3c/#", qos=1)
def on_disconnect(client, userdata, flags, reason_code, properties):
reason = getattr(properties, "ReasonString", "") if properties else ""
print(ts(), "DISCONNECT", reason_code, f"(0x{reason_code.value:02X})", reason)
client = mqtt.Client(
mqtt.CallbackAPIVersion.VERSION2,
client_id="disconnect-debug-5a3c",
protocol=mqtt.MQTTv5,
)
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.reconnect_delay_set(min_delay=1, max_delay=60)
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_forever(retry_first_connection=True)
Um aus einem anderen Terminal die Sicht des Brokers auf einen Client zu verfolgen, abonnieren Sie dessen Topic für den Verbindungsstatus:
mosquitto_sub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
-u YOUR_USERNAME -P YOUR_PASSWORD -i YOUR_MONITOR_CLIENT_ID \
-t '$SYS/broker/connection/YOUR_CLIENT_ID/state' -v
Setzen Sie das Topic in einfache Anführungszeichen, damit die Shell $SYS nicht expandiert. Der Leitfaden zu MQTT-$SYS-Topics erklärt, was Sie auf diese Weise noch überwachen können. Da der Broker Client IDs an Zugangsdaten bindet, braucht die Überwachungsverbindung eine eigene gültige Client ID; der browserbasierte MQTT-Client im Portal ist eine einfache Alternative für einen schnellen Blick.
Reconnect-Logik, die nichts verschlimmert
Automatische Reconnects sind unverzichtbar, doch eine unbedachte Implementierung macht aus einem Problem viele:
- Verwenden Sie exponentiellen Backoff mit Jitter, damit sich eine Flotte nach einem Ausfall nicht im Gleichschritt neu verbindet.
- Versuchen Sie es bei Autorisierungsfehlern nicht erneut. Die Codes
0x86und0x87beheben sich nicht von selbst, und wiederholte fehlgeschlagene Anmeldungen können zur Sperrung Ihrer IP führen. - Abonnieren Sie in
on_connecterneut, nicht nur einmal beim Start, es sei denn, Sie verlassen sich auf eine persistente Session. - Verwenden Sie einen Last Will, damit andere Systeme erfahren, wenn ein Gerät unerwartet ausfällt. Siehe MQTT Last Will and Testament.
Trennungen mit ConnectMQ diagnostizieren
ConnectMQ bietet Ihnen Einblick auf Broker-Seite, der selbst gehosteten Setups oft fehlt. Das Portal-Dashboard und die Geräteansicht zeigen, welche Clients verbunden sind, der Live-Topic-Explorer zeigt, was sie veröffentlichen, und über das Topic $SYS/broker/connection/{clientId}/state können Ihre eigenen Tools Verbindungsänderungen verfolgen. MQTT-5-Clients erhalten Reason Codes bei Kontingent- und Protokollverletzungen, sodass Sie sehen, warum eine Trennung erfolgte, statt zu raten. Hintergründe dazu, was ein MQTT-Broker während der Lebensdauer einer Verbindung macht, finden Sie in unserem Erklärartikel, das vollständige Protokoll im MQTT-Tutorial.
Stabile Verbindungen mit ConnectMQ
Ein verwalteter MQTT-Broker nimmt Ihnen die Verfügbarkeit des Brokers ab, sodass Sie sich auf das Verhalten der Clients konzentrieren können. Erstellen Sie unter app.connectmq.com einen kostenlosen Serverless-Broker, ganz ohne Kreditkarte, und testen Sie Ihre Reconnect-Logik gegen echte Limits, bevor Sie ausliefern. Vergleichen Sie die Optionen in unserem Leitfaden zum Markt für Cloud-MQTT-Broker.
Häufig gestellte Fragen
Warum trennt mein MQTT-Client alle paar Sekunden die Verbindung?
Die häufigste Ursache ist ein anderer Client mit derselben Client ID. Jede Verbindung wirft die andere hinaus, und beide verbinden sich automatisch neu. Geben Sie jedem Client eine eindeutige ID.
Welchen Keep-Alive-Wert sollte ich verwenden?
Für die meisten Einsätze eignen sich 30 bis 120 Sekunden. Wählen Sie einen Wert unterhalb des Idle-Timeouts Ihres Netzwerks und stellen Sie sicher, dass die Netzwerkschleife des Clients ununterbrochen läuft, damit PINGREQ tatsächlich gesendet wird.
Woran erkenne ich, ob Broker oder Client die Verbindung geschlossen hat?
Verbinden Sie sich per MQTT 5. Hat der Broker sie geschlossen, erhält der Client ein DISCONNECT-Paket mit Reason Code; ist der Socket einfach abgebrochen, meldet der Client einen Netzwerkfehler ohne Reason Code.
Kann eine große Nachricht Trennungen verursachen?
Ja. Überschreitet ein Paket die maximale Größe des Brokers, schließt der Broker die Verbindung, und sendet der Client dieselbe Nachricht nach dem Reconnect erneut, wird er wieder getrennt. Prüfen Sie die Payload-Größen gegen das Limit Ihres Brokers.



