ESP32 und Arduino

PubSubClient rc=-2 und weitere State-Codes erklärt (mit Lösungen)

PubSubClient meldet nur "failed, rc=-2"? Diese Anleitung entschlüsselt jeden State-Code von -4 bis 5 und liefert erprobte Lösungen für Probleme mit DNS, Port, TLS, Client ID und Zugangsdaten.

Serieller Monitor mit einem PubSubClient-Verbindungsfehler rc=-2 neben einem ESP32-Board
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

failed, rc=-2 im seriellen Monitor ist der häufigste PubSubClient-Fehler, und die Meldung allein verrät sehr wenig. PubSubClient rc=-2 bedeutet, dass die TCP- (oder TLS-)Verbindung zum Broker nie aufgebaut wurde. Das Problem liegt daher fast immer bei DNS, Port, Netzwerk oder Zertifikat, nicht bei MQTT selbst. Diese Anleitung entschlüsselt jeden State-Code von -4 bis 5 und liefert für jeden eine Lösung.

Woher der rc-Wert stammt

PubSubClient speichert das Ergebnis des letzten Verbindungsversuchs in einer internen Statusvariable, die Sie mit mqtt.state() auslesen. Die meisten Beispiel-Sketches geben sie aus, wenn connect() den Wert false zurückliefert:

if (!mqtt.connect(clientId)) {
  Serial.print("failed, rc=");
  Serial.println(mqtt.state());
}

Die Werte sind als Konstanten in PubSubClient.h definiert. Negative Werte stammen aus der Bibliothek und der Netzwerkschicht. Positive Werte sind die Return Codes, die der Broker in seinem CONNACK-Paket zurückgeschickt hat, wie in der MQTT-3.1.1-Spezifikation festgelegt.

rc Konstante Schicht Bedeutung im Klartext
-4 MQTT_CONNECTION_TIMEOUT Bibliothek Socket geöffnet, aber kein CONNACK (oder keine Ping-Antwort) rechtzeitig
-3 MQTT_CONNECTION_LOST Netzwerk Eine bestehende Verbindung ist abgebrochen
-2 MQTT_CONNECT_FAILED Netzwerk Socket konnte gar nicht geöffnet werden
-1 MQTT_DISCONNECTED Bibliothek Client ist sauber getrennt
0 MQTT_CONNECTED Broker Verbunden
1 MQTT_CONNECT_BAD_PROTOCOL Broker Protokollversion nicht akzeptiert
2 MQTT_CONNECT_BAD_CLIENT_ID Broker Client ID abgelehnt
3 MQTT_CONNECT_UNAVAILABLE Broker Broker kann derzeit keine Verbindungen annehmen
4 MQTT_CONNECT_BAD_CREDENTIALS Broker Benutzername oder Passwort falsch
5 MQTT_CONNECT_UNAUTHORIZED Broker Keine Berechtigung zum Verbinden

Die zentrale Erkenntnis: Bei negativen Codes hat der Broker Sie entweder nie gesehen oder nie geantwortet. Bei positiven Codes hat der Broker Ihr CONNECT-Paket empfangen und bewusst abgelehnt.

PubSubClient rc=-2 beheben

Da rc=-2 immer dann gemeldet wird, wenn client.connect(host, port) auf dem zugrunde liegenden Netzwerkobjekt fehlschlägt, gibt es viele mögliche Ursachen. Gehen Sie sie in dieser Reihenfolge durch.

1. Das WLAN ist gar nicht verbunden

Ein Aufruf von mqtt.connect(), bevor WiFi.status() == WL_CONNECTED gilt, liefert immer -2. Das passiert auch, wenn der Access Point Sie getrennt hat und Ihre Schleife nur MQTT prüft. Prüfen Sie in jedem Durchlauf zuerst das WLAN und verbinden Sie es neu, bevor Sie MQTT anfassen.

2. DNS schlägt fehl oder der Hostname ist falsch

Tippfehler wie broker.connectmq.com mit Leerzeichen am Ende, mqtt://broker.connectmq.com (eine URL statt eines Hostnamens) oder ein http://-Präfix scheitern allesamt stillschweigend. setServer() erwartet einen reinen Hostnamen oder eine IPAddress. Testen Sie DNS direkt:

IPAddress ip;
if (WiFi.hostByName("broker.connectmq.com", ip)) {
  Serial.print("Resolved to ");
  Serial.println(ip);
} else {
  Serial.println("DNS lookup failed");
}

Schlägt DNS fehl, prüfen Sie, ob DHCP Ihnen einen DNS-Server zugewiesen hat, oder legen Sie einen explizit mit WiFi.config() fest.

3. Falscher Port für den Client-Typ

Das ist der klassische Fehler. Port und Netzwerk-Client müssen zusammenpassen:

Port Transport Zu verwendender Arduino-Client
1883 Reines MQTT über TCP WiFiClient
8883 MQTT über TLS WiFiClientSecure
8083 / 8084 MQTT über WebSocket Von PubSubClient nicht unterstützt

Ein WiFiClient, der auf 8883 zeigt, öffnet einen TCP-Socket und hängt dann oder scheitert, weil der Broker einen TLS-Handshake erwartet. Das zeigt sich oft als -2 oder -4. Ein WiFiClientSecure, der auf 1883 zeigt, scheitert am Handshake und liefert -2. PubSubClient beherrscht überhaupt keine WebSockets, daher sind die Ports 8083 und 8084 für Browser und Tools gedacht, wie sie in MQTT über WebSocket beschrieben werden.

4. Probleme mit dem TLS-Zertifikat

Mit WiFiClientSecure wird auch eine fehlgeschlagene Zertifikatsprüfung als rc=-2 gemeldet. Häufige Ursachen:

  • Kein CA-Zertifikat gesetzt. Rufen Sie auf dem ESP32 setCACert() mit dem Root-Zertifikat auf, das das Broker-Zertifikat signiert hat. ConnectMQ verwendet Let's Encrypt, das Root-Zertifikat ist also ISRG Root X1.
  • Pinning eines Leaf- oder Zwischenzertifikats, das inzwischen erneuert wurde. Let's-Encrypt-Zertifikate sind kurzlebig; pinnen Sie das Root-Zertifikat, nicht das Leaf.
  • Falsche Systemzeit auf dem ESP8266. BearSSL prüft die Gültigkeitsdaten, synchronisieren Sie die Zeit daher vor dem Verbinden mit configTime().
  • Zu wenig Speicher. Der TLS-Handshake braucht einen ordentlichen Teil des Heaps; auf dem ESP8266 kann ein großer MQTT-Puffer zusammen mit TLS ihn erschöpfen.

Auf dem ESP32 können Sie nach einem fehlgeschlagenen Versuch den zugrunde liegenden TLS-Fehler ausgeben:

char err[128];
int code = netClient.lastError(err, sizeof(err));
Serial.printf("TLS error %d: %s\n", code, err);

Um das Problem einzugrenzen, rufen Sie vorübergehend netClient.setInsecure() auf. Verbindet es sich dann, liegt das Problem in Ihrer Zertifikatskonfiguration. Liefern Sie niemals Firmware mit setInsecure() aus.

5. Das Netzwerk blockiert ausgehendes MQTT

Firmen-, Schul- und manche Gastnetzwerke blockieren die ausgehenden Ports 1883 und 8883, ebenso viele Produktionsnetze, die nach Zonen und Conduits gemäß IEC 62443 segmentiert sind. Testen Sie denselben Sketch an einem Handy-Hotspot. Funktioniert er dort, lassen Sie den Port freigeben oder verlegen Sie das Gerät in ein anderes Netzwerksegment; in der Fabrik stimmen Sie das mit der OT-Sicherheit ab.

6. Zu häufige Verbindungsversuche

Sieht der Broker wiederholte fehlgeschlagene Versuche von Ihrer IP-Adresse, lehnt er Verbindungen möglicherweise vorübergehend ab. ConnectMQ sperrt zum Beispiel IP-Adressen nach wiederholten fehlgeschlagenen Logins, um seine Mandanten zu schützen. Eine Reconnect-Schleife ohne Pause kann aus einem einzigen falschen Passwort eine Sperre machen, die dann wie rc=-2 aussieht. Warten Sie zwischen den Versuchen immer mindestens einige Sekunden und verlängern Sie die Wartezeit nach mehreren Fehlschlägen weiter.

rc=-4 beheben (Verbindungs-Timeout)

Hier wurde der Socket geöffnet, aber das CONNACK traf nicht innerhalb des Socket-Timeouts (standardmäßig 15 Sekunden) ein. Typische Ursachen:

  • Ein einfacher WiFiClient auf einem TLS-Port, wie oben beschrieben.
  • Schwaches WLAN-Signal mit hohem Paketverlust. Geben Sie WiFi.RSSI() aus; alles um -80 dBm oder schwächer ist unzuverlässig.
  • Blockierender Code. War die Verbindung bereits aufgebaut, kann -4 auch später auftreten, wenn loop() nicht oft genug aufgerufen wird, um Keep-Alive-Pings zu beantworten.

rc=-3 beheben (Verbindung verloren)

Die Verbindung hat funktioniert und ist dann abgebrochen. Achten Sie auf:

  • Doppelte Client IDs. Verbindet sich ein zweites Gerät mit derselben ID, trennt der Broker das erste. Zwei Boards mit demselben Sketch werfen sich abwechselnd gegenseitig hinaus. Erzeugen Sie die IDs aus der MAC-Adresse.
  • Abgelaufenes Keep Alive. Lange delay()-Aufrufe oder langsame Sensorabfragen lassen mqtt.loop() verhungern.
  • Zu große oder zu häufige Nachrichten. Broker setzen Limits durch. Auf dem öffentlichen MQTT-Broker unter broker.connectmq.com, der nur für Tests und Prototypen gedacht ist, sind Clients auf 64 KB pro Nachricht und 10 Nachrichten pro Sekunde begrenzt, und Überschreitungen können die Sitzung beenden.

Die positiven Codes beheben (1 bis 5)

rc=1: Falsches Protokoll

PubSubClient sendet standardmäßig MQTT 3.1.1. Diesen Code sehen Sie nur, wenn Sie mit MQTT_VERSION auf 3.1 kompiliert haben und der Broker das ablehnt. Entfernen Sie die Überschreibung.

rc=2: Client ID abgelehnt

Meist ist eine leere Client ID schuld. Der öffentliche MQTT-Broker von ConnectMQ verlangt auch bei anonymen Verbindungen eine nicht leere Client ID. Auf einem privaten ConnectMQ Broker sind Client IDs an die im Portal ausgestellten Zugangsdaten gebunden, verwenden Sie also genau die Client ID, die Sie erhalten haben.

rc=3: Server nicht verfügbar

Der Broker läuft, nimmt aber keine Verbindungen an, etwa während einer Wartung oder wenn ein Verbindungskontingent erreicht ist. Warten Sie und versuchen Sie es erneut. Bleibt der Fehler bei Ihrem eigenen Broker bestehen, prüfen Sie, ob Sie das Verbindungslimit Ihres Plans überschritten haben.

rc=4: Falscher Benutzername oder falsches Passwort

Kopieren Sie die Zugangsdaten erneut aus dem Portal und achten Sie auf unsichtbare Zeichen. Denken Sie daran, dass connect(id, user, pass) die Client ID zuerst erwartet; vertauschte Parameter sind überraschend häufig.

rc=5: Nicht autorisiert

Der Broker hat die Zugangsdaten verstanden, lehnt diesen Client aber ab, zum Beispiel weil Benutzername und Client ID nicht zusammengehören. Prüfen Sie alle drei Werte erneut.

Eine Connect-Funktion mit Diagnose

Fügen Sie dies in einen beliebigen Sketch ein, um statt einer bloßen Zahl eine lesbare Ursache zu erhalten:

const char* mqttStateText(int s) {
  switch (s) {
    case -4: return "timeout (no CONNACK) - check port/TLS match and signal";
    case -3: return "connection lost - duplicate client ID or keep alive";
    case -2: return "socket failed - Wi-Fi, DNS, port, firewall or TLS cert";
    case -1: return "disconnected";
    case 0:  return "connected";
    case 1:  return "bad protocol version";
    case 2:  return "client ID rejected - empty or not allowed";
    case 3:  return "server unavailable - retry later";
    case 4:  return "bad username or password";
    case 5:  return "not authorised";
    default: return "unknown";
  }
}

bool connectWithDiagnostics() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("Wi-Fi not connected, skipping MQTT");
    return false;
  }
  if (mqtt.connect(DEVICE_ID)) {
    Serial.println("MQTT connected");
    return true;
  }
  int s = mqtt.state();
  Serial.printf("MQTT failed rc=%d: %s\n", s, mqttStateText(s));
  return false;
}

Checkliste zur schnellen Eingrenzung

  1. Erreicht Ihr Computer den Broker? Führen Sie mosquitto_sub -h broker.connectmq.com -p 1883 -i test-$RANDOM -t "connectmq/demo/check/#" -v aus. Schlägt das fehl, liegt das Problem an Ihrem Netzwerk, nicht am Board.
  2. Löst das Board den Hostnamen auf? Verwenden Sie das DNS-Snippet von oben.
  3. Verbindet es sich auf 1883 mit WiFiClient und einer anonymen, eindeutigen Client ID? Wenn ja, liegt das Problem bei TLS oder den Zugangsdaten.
  4. Verbindet es sich auf 8883 mit setInsecure()? Wenn ja, korrigieren Sie das CA-Zertifikat.
  5. Verbindet es sich mit dem CA-Zertifikat, scheitert aber an den Zugangsdaten? Prüfen Sie Benutzer, Passwort und Client ID erneut.

Ist die Verbindung erst einmal da, stoßen viele als Nächstes auf die Nachrichtengröße; siehe PubSubClient-Puffergröße. Eine vollständige Einführung in die Bibliothek bietet unser PubSubClient-Arduino-Tutorial, und ein komplettes Projekt finden Sie im ESP32-IoT-Leitfaden.

Schluss mit der Jagd nach rc-Codes dank verwaltetem MQTT-Broker

Viele rc=-2- und rc=-4-Fehler stammen von selbst gehosteten Brokern mit abgelaufenen Zertifikaten, geschlossenen Firewall-Ports oder abgestürzten Diensten. Ein verwalteter MQTT-Broker wie ConnectMQ nimmt Ihnen diese Variablen ab: TLS auf 8883 mit automatisch erneuertem Let's-Encrypt-Zertifikat, für Sie generierte Zugangsdaten und ein MQTT-Client im Browser direkt im Portal, mit dem Sie prüfen können, ob die Broker-Seite funktioniert, bevor Sie das Gerät debuggen. Starten Sie einen kostenlosen Serverless Broker unter app.connectmq.com, ohne Kreditkarte.

Häufig gestellte Fragen

Was bedeutet rc=-2 bei PubSubClient?

Es bedeutet, dass die Netzwerkverbindung zum Broker nicht geöffnet werden konnte. Der Broker hat Ihr CONNECT-Paket nie erhalten, prüfen Sie also WLAN, DNS, den Port und bei TLS das CA-Zertifikat.

Warum erhalte ich rc=-2 nur auf Port 8883?

Ihr TLS-Setup schlägt fehl. Stellen Sie sicher, dass Sie WiFiClientSecure verwenden, das richtige Root-Zertifikat laden (ISRG Root X1 bei Let's-Encrypt-Brokern) und auf dem ESP8266 die Uhrzeit vor dem Verbinden setzen.

Mein Board verbindet sich und zeigt dann alle paar Sekunden rc=-3. Warum?

Meistens verwendet ein anderes Gerät oder Tool dieselbe Client ID, sodass der Broker eine Sitzung ständig durch die andere ersetzt. Geben Sie jedem Gerät eine eindeutige ID, zum Beispiel auf Basis seiner MAC-Adresse.

Ist rc=5 etwas anderes als rc=4?

Ja. rc=4 bedeutet, dass Benutzername oder Passwort falsch sind. rc=5 bedeutet, dass die Zugangsdaten verstanden wurden, dieser Client sich aber nicht verbinden darf, oft weil die Client ID nicht zu den Zugangsdaten passt.

Verwandte Artikel

ESP32 NTP MQTT Zeitstempel: genaue Uhrzeit in jeder Nachricht

Synchronisieren Sie die ESP32-Uhr per NTP, formatieren Sie Zeitstempel in ISO 8601 und Epoch-Millisekunden und hängen Sie sie an MQTT-Payloads, damit Messwerte ihren echten Erfassungszeitpunkt behalten, auch wenn sie verspätet veröffentlicht werden.

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.