Wenn sich Ihr ESP32 nicht mit einem MQTT-Broker verbinden kann, steckt fast immer eines von einem Dutzend vorhersehbarer Probleme dahinter, vom falschen WLAN-Band bis zum TLS-Client auf einem unverschlüsselten Port. Dieser Leitfaden gibt Ihnen eine systematische Prüfreihenfolge, erklärt, was jeder PubSubClient-Fehlercode bedeutet, und zeigt, wie Sie jede Lösung gegen broker.connectmq.com bestätigen.
Beginnen Sie mit dem Fehlercode
Bevor Sie etwas ändern, finden Sie heraus, wo die Verbindung scheitert. PubSubClient liefert den Grund über client.state(). Geben Sie ihn jedes Mal aus, wenn connect() false zurückgibt:
if (!mqtt.connect(clientId.c_str())) {
Serial.printf("MQTT connect failed, state=%d\n", mqtt.state());
}
state() |
Konstante | Was es meistens bedeutet |
|---|---|---|
| -4 | MQTT_CONNECTION_TIMEOUT |
Der Server hat nicht innerhalb der Keepalive-Periode geantwortet |
| -3 | MQTT_CONNECTION_LOST |
Die Verbindung ist nach dem Aufbau abgebrochen |
| -2 | MQTT_CONNECT_FAILED |
Die TCP- oder TLS-Verbindung konnte gar nicht geöffnet werden |
| -1 | MQTT_DISCONNECTED |
Der Client ist sauber getrennt |
| 1 | MQTT_CONNECT_BAD_PROTOCOL |
Der Broker akzeptiert die Protokollversion nicht |
| 2 | MQTT_CONNECT_BAD_CLIENT_ID |
Client ID abgelehnt |
| 3 | MQTT_CONNECT_UNAVAILABLE |
Broker nicht verfügbar |
| 4 | MQTT_CONNECT_BAD_CREDENTIALS |
Falscher Benutzername oder falsches Passwort |
| 5 | MQTT_CONNECT_UNAUTHORIZED |
Client nicht autorisiert |
Die Aufteilung ist hilfreich: Negative Codes bedeuten, dass das Problem unterhalb von MQTT liegt (Netzwerk, DNS, TCP, TLS), positive Codes bedeuten, dass der Broker geantwortet und Sie abgewiesen hat. Ein -2 führt Sie zu den Lösungen 1–6, eine 4 oder 5 zu den Lösungen 7–9.
Zuerst beweisen, dass die Broker-Seite funktioniert
Schließen Sie den Broker als Ursache aus, bevor Sie die Firmware anfassen. Führen Sie auf einem Rechner im selben Netzwerk aus:
mosquitto_sub -h broker.connectmq.com -p 1883 -i pc-test-4821 -t 'connectmq/demo/4821/#' -v
In einem zweiten Terminal:
mosquitto_pub -h broker.connectmq.com -p 1883 -i pc-pub-4821 -t connectmq/demo/4821/hello -m test
Kommt die Nachricht an, funktionieren Broker und Internetpfad, und das Problem liegt beim ESP32 oder in seinem Netzwerksegment. Kommt sie auch auf Ihrem Rechner nicht an, prüfen Sie zuerst die Firewall Ihres Netzwerks. Die Seite zum öffentlichen MQTT-Broker listet die Ports und Limits auf, gegen die Sie testen können.
Lösungen auf Netzwerkebene (negative Statuscodes)
1. Sicherstellen, dass das WLAN wirklich auf 2,4 GHz verbunden ist
Der ESP32 (mit Ausnahme neuerer Varianten mit 5-GHz-Unterstützung) kommuniziert nur mit 2,4-GHz-Netzen. Ein Dualband-Router mit einer SSID für beide Bänder funktioniert meist, eine reine 5-GHz-SSID dagegen nie. Prüfen Sie auch die Reihenfolge: Ein Aufruf von mqtt.connect() vor WiFi.status() == WL_CONNECTED scheitert immer mit -2. Geben Sie WiFi.localIP() und WiFi.RSSI() aus; ein Signal schwächer als etwa -80 dBm führt zu sporadischen Fehlern, die wie Broker-Probleme aussehen.
2. Die DNS-Auflösung prüfen
Wenn der Hostname nicht aufgelöst wird, startet die TCP-Verbindung gar nicht erst. Testen Sie das direkt:
IPAddress ip;
if (WiFi.hostByName("broker.connectmq.com", ip)) {
Serial.println(ip);
} else {
Serial.println("DNS lookup failed");
}
Ein Fehler hier deutet auf den per DHCP gelieferten DNS-Server oder auf eine statische IP-Konfiguration ohne DNS-Eintrag hin. Wenn Sie WiFi.config() für eine statische Adresse verwenden, übergeben Sie auch das Gateway und einen DNS-Server.
3. Den Port passend zur Client-Klasse wählen
Das ist der mit Abstand häufigste Fehler. WiFiClient spricht unverschlüsseltes TCP und muss Port 1883 verwenden. WiFiClientSecure spricht TLS und muss Port 8883 verwenden. Eine Vermischung führt zu -2 oder -4 ohne weiteren Hinweis.
| Client-Klasse | Port | Transport |
|---|---|---|
WiFiClient |
1883 | Unverschlüsseltes MQTT über TCP |
WiFiClientSecure |
8883 | MQTT über TLS |
| WebSocket-Bibliotheken | 8083 / 8084 (Pfad /mqtt) |
MQTT über WebSocket / Secure WebSocket |
PubSubClient beherrscht kein WebSocket, die Ports 8083 und 8084 sind also nur für Browser-Clients und WebSocket-fähige Bibliotheken gedacht.
4. Die TLS-Zertifikatsprüfung reparieren
Mit WiFiClientSecure lässt ein fehlendes oder falsches CA-Zertifikat den Handshake stillschweigend scheitern. ConnectMQ verwendet ein Let's-Encrypt-Zertifikat, laden Sie also das Root ISRG Root X1 mit setCACert(). Um zu bestätigen, dass TLS der Übeltäter ist, rufen Sie vorübergehend secureClient.setInsecure() auf: Funktioniert die Verbindung plötzlich, ist Ihre CA falsch. Liefern Sie setInsecure() niemals in der Produktion aus. Lesen Sie den TLS-Fehler für Details mit secureClient.lastError(buf, sizeof(buf)) aus und sehen Sie sich für ein vollständiges sicheres Setup ESP32 MQTT über SSL/TLS an.
5. TLS genug Speicher und Zeit geben
TLS-Handshakes brauchen einige Dutzend Kilobyte Heap. Wenn Ihr Sketch große Puffer, Bilddaten oder mehrere sichere Clients reserviert, scheitert der Handshake mit -2. Geben Sie direkt vor dem Verbinden ESP.getFreeHeap() aus. Prüfen Sie auch die Uhr: Die Zertifikatsprüfung vergleicht Datumsangaben, und manche Bibliotheken setzen eine gültige Uhrzeit voraus. Eine NTP-Synchronisation mit configTime() vor dem Verbinden vermeidet eine ganze Klasse rätselhafter Fehler.
6. Den Netzwerkpfad auf blockierte Ports prüfen
Gast-WLANs, Firmennetze und manche mobilen Hotspots blockieren ausgehende Verbindungen auf 1883 oder 8883. Wenn der obige Rechner-Test nur aus einem anderen Netz funktioniert hat, probieren Sie den ESP32 an einem Handy-Hotspot. Verbindet er sich dort, filtert das ursprüngliche Netz MQTT-Ports, und der Netzwerkadministrator muss sie freigeben. In Werksnetzen, die nach dem Zonen-und-Conduit-Modell der IEC 62443 segmentiert sind, ist das der Normalfall: Beantragen Sie gezielt ausgehendes TCP 8883 vom OT-Segment zum Broker-Host, statt das Gerät für den Test in ein anderes Netz zu hängen.
Lösungen auf Broker-Ebene (positive Statuscodes)
7. Eine nicht leere, eindeutige Client ID verwenden
Jeder Client braucht seine eigene Client ID. Zwei Geräte, die mit derselben fest codierten ID geflasht wurden, werfen sich gegenseitig immer wieder vom Broker, was wie zufällige Verbindungsabbrüche mit Status -3 aussieht. Eine leere Client ID wird ebenfalls von vielen Brokern abgelehnt, auch vom öffentlichen MQTT-Broker broker.connectmq.com. Leiten Sie die ID aus der MAC-Adresse des Chips ab:
String clientId = "esp32-" + String((uint32_t)ESP.getEfuseMac(), HEX);
8. Exakt die Zugangsdaten und Client ID aus dem Portal verwenden
Bei einem privaten ConnectMQ-Broker ist die Client ID an die ausgegebenen Zugangsdaten gebunden. Wenn Sie sich eine eigene Client ID ausdenken und dabei den generierten Benutzernamen und das Passwort verwenden, lehnt der Broker die Verbindung mit Code 5 ab, obwohl das Passwort stimmt. Kopieren Sie alle drei Werte aus dem Portal: YOUR_CLIENT_ID, YOUR_USERNAME, YOUR_PASSWORD. Achten Sie beim Einfügen in den Code auf unsichtbare Leerzeichen am Ende.
9. Wiederholungsstürme stoppen, bevor Sie gesperrt werden
Eine Reconnect-Schleife ohne Verzögerung kann den Broker mit vielen Verbindungsversuchen pro Sekunde treffen. Mit falschen Zugangsdaten ist das besonders schädlich, weil ConnectMQ im Rahmen seines Flood-Schutzes IP-Adressen nach wiederholten fehlgeschlagenen Logins sperrt. Warten Sie zwischen den Versuchen und vergrößern Sie die Wartezeit nach jedem Fehlschlag:
unsigned long nextAttempt = 0;
unsigned long backoff = 2000;
void ensureMqtt() {
if (mqtt.connected() || millis() < nextAttempt) return;
if (mqtt.connect(clientId.c_str())) {
backoff = 2000;
mqtt.subscribe("connectmq/demo/4821/cmd");
} else {
Serial.printf("connect failed, state=%d, retry in %lu ms\n", mqtt.state(), backoff);
nextAttempt = millis() + backoff;
backoff = min(backoff * 2, 60000UL);
}
}
Die nicht blockierende Struktur hält außerdem loop() reaktionsfähig. Der Leitfaden zum ESP32 MQTT Reconnect geht tiefer auf robuste Wiederverbindungslogik ein.
Lösungen für Verbindungen, die nach dem Aufbau abbrechen
10. mqtt.loop() oft genug aufrufen
PubSubClient sendet Keepalive-Pings und liest eingehende Pakete nur innerhalb von loop(). Ein langes delay() oder eine blockierende Sensorabfrage, die länger dauert als das Keepalive-Intervall (standardmäßig 15 Sekunden), lässt den Broker glauben, der Client sei tot, und Sie sehen -3 oder -4. Ersetzen Sie lange Verzögerungen durch millis()-Timer oder erhöhen Sie das Keepalive mit mqtt.setKeepAlive(30). Wenn das Board außerdem neu startet, lesen Sie über ESP32-Task-Watchdog-Resets in MQTT-Projekten.
11. Den Puffer für große Nachrichten vergrößern
Der Standard-Paketpuffer von PubSubClient beträgt 256 Byte, einschließlich Topic und Header. Ein größerer Publish scheitert lautlos: publish() gibt false zurück, und eine zu große eingehende Nachricht wird verworfen. Rufen Sie vor dem Verbinden mqtt.setBufferSize(1024) auf, bemessen nach Ihrer größten Nachricht.
12. Die Limits des öffentlichen Brokers beachten
Der öffentliche MQTT-Broker broker.connectmq.com erlaubt 64 KB pro Nachricht, 10 Nachrichten pro Sekunde pro Client, 10 Abonnements pro Client und bis zu 8 Topic-Ebenen. Ein Sketch, der in einer engen Schleife veröffentlicht oder viele Topics abonniert, kann wegen Überschreitung getrennt werden. Drosseln Sie das Veröffentlichen, verwenden Sie ein Wildcard-Abonnement statt vieler einzelner und halten Sie Topics wie connectmq/demo/4821/room/temp kurz.
Ein Diagnose-Sketch
Flashen Sie diesen Sketch, wenn Sie nicht weiterkommen. Er meldet jede Stufe einzeln, sodass Sie genau sehen, wo die Kette reißt:
#include <WiFi.h>
#include <PubSubClient.h>
const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* HOST = "broker.connectmq.com";
WiFiClient net;
PubSubClient mqtt(net);
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) { delay(250); Serial.print('.'); }
Serial.printf("\nWi-Fi OK ip=%s rssi=%d\n", WiFi.localIP().toString().c_str(), WiFi.RSSI());
IPAddress ip;
if (!WiFi.hostByName(HOST, ip)) { Serial.println("DNS FAILED"); return; }
Serial.printf("DNS OK %s\n", ip.toString().c_str());
if (!net.connect(HOST, 1883)) { Serial.println("TCP 1883 FAILED"); return; }
Serial.println("TCP OK");
net.stop();
String id = "esp32-diag-" + String((uint32_t)ESP.getEfuseMac(), HEX);
mqtt.setServer(HOST, 1883);
if (mqtt.connect(id.c_str())) {
Serial.println("MQTT OK");
mqtt.publish("connectmq/demo/4821/diag", "hello from diag");
} else {
Serial.printf("MQTT FAILED state=%d\n", mqtt.state());
}
}
void loop() { mqtt.loop(); }
Lassen Sie mosquitto_sub auf connectmq/demo/4821/# laufen, dann sehen Sie die Diagnosenachricht in dem Moment, in dem alles funktioniert.
Wenn es mit dem öffentlichen MQTT-Broker funktioniert, aber nicht in der Produktion
Die meisten Produktionsfehler laufen auf die Lösungen 3, 4 und 8 hinaus: Wechsel auf Port 8883 ohne Wechsel zu WiFiClientSecure, ein vergessenes CA-Zertifikat oder eine selbst ausgedachte Client ID mit Zugangsdaten aus dem Portal. Ändern Sie immer nur eine Sache auf einmal und lassen Sie die Ausgabe des Fehlercodes aktiv. Das ESP32-IoT-Tutorial zeigt ein vollständiges Projekt, das sich in beiden Modi sauber verbindet, und was ein MQTT-Broker macht erklärt, warum der Broker bestimmte Verbindungen ablehnt.
Bringen Sie Ihren ESP32 mit ConnectMQ online
Sobald sich das Gerät mit dem öffentlichen MQTT-Broker verbindet, der für Tests und Prototypen gedacht ist, ziehen Sie es auf einen privaten Broker im kostenlosen Serverless-Tarif unter app.connectmq.com um, ohne Kreditkarte. Der MQTT-Client im Browser und der Live-Topic-Explorer des Portals machen es leicht, den Datenverkehr von Geräte- und Serverseite aus zu bestätigen. ConnectMQ ist ein verwalteter MQTT-Broker mit TLS auf 8883 ab Werk, sodass das einzige Zertifikat, das Sie auf dem ESP32 brauchen, das öffentliche Let's-Encrypt-Root ist.
Häufig gestellte Fragen
Was bedeutet PubSubClient rc=-2?
Es bedeutet, dass die TCP- oder TLS-Verbindung nicht geöffnet werden konnte und der Broker daher nie ein MQTT-Paket gesehen hat. Prüfen Sie WLAN, DNS, die Kombination aus Port und Client-Klasse, das CA-Zertifikat und den freien Heap.
Warum verbindet sich mein ESP32 und trennt sich dann alle paar Sekunden?
Meist verwendet ein anderes Gerät dieselbe Client ID, oder mqtt.loop() wird nicht oft genug aufgerufen, um Keepalive-Pings zu senden. Geben Sie jedem Gerät eine eindeutige ID und entfernen Sie lange blockierende Verzögerungen.
Kann ich Port 8083 oder 8084 mit PubSubClient verwenden?
Nein. Das sind WebSocket-Ports, und PubSubClient spricht MQTT nur über reines TCP oder TLS. Verwenden Sie 1883 mit WiFiClient oder 8883 mit WiFiClientSecure.
Warum werden meine Zugangsdaten abgelehnt, obwohl das Passwort stimmt?
Bei einem privaten Broker mit ausgegebenen Zugangsdaten ist die Client ID an diese gebunden. Verwenden Sie exakt die im Portal angezeigte Client ID zusammen mit dem generierten Benutzernamen und Passwort.



