MQTT-Grundlagen

Warum Ihr MQTT-Client ständig die Verbindung trennt (und wie Sie es beheben)

Reconnect-Schleifen gehören zu den häufigsten MQTT-Problemen. Lernen Sie die fünf üblichen Ursachen kennen, von doppelten Client IDs bis zu Keep-Alive-Timeouts und zu großen Paketen, und folgen Sie einem Diagnoseablauf, der Ihre Ursache eingrenzt.

Diagramm eines Geräts, das wiederholt abbricht und sich neu verbindet, um zu zeigen, warum ein MQTT-Client ständig trennt
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

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 minutenlang delay() 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

  1. Aktivieren Sie das Client-Logging. In Paho client.enable_logger(), in den Mosquitto-Tools -d, in MQTT.js setzen Sie DEBUG=mqttjs*.
  2. Verbinden Sie sich per MQTT 5 und protokollieren Sie Reason Code und Reason String jedes DISCONNECT.
  3. Erfassen Sie die Zeitstempel von Verbindungsaufbau und Trennung und vergleichen Sie das Intervall mit Ihrem Keep Alive.
  4. 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.
  5. Reproduzieren Sie mit einem minimalen Client. Starten Sie mosquitto_sub mit denselben Zugangsdaten im selben Netzwerk. Bleibt es verbunden, liegt das Problem in Ihrer Anwendung.
  6. Ä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 0x86 und 0x87 beheben sich nicht von selbst, und wiederholte fehlgeschlagene Anmeldungen können zur Sperrung Ihrer IP führen.
  • Abonnieren Sie in on_connect erneut, 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.

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

MQTT vs. CoAP: Pub/Sub über TCP vs. Request/Response über UDP

MQTT und CoAP zielen beide auf eingeschränkte IoT-Geräte, verfolgen aber gegensätzliche Ansätze: Broker-basiertes Pub/Sub über TCP gegenüber RESTful Request/Response über UDP. So schneiden sie im Vergleich ab, und so wissen Sie, wann Sie welches einsetzen.

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.