ESP32 et Arduino

L'ESP32 ne se connecte pas au broker MQTT : 12 solutions qui fonctionnent vraiment

Un guide de dépannage méthodique pour les cas où votre ESP32 ne se connecte pas à un broker MQTT : Wi-Fi, DNS, ports, certificats TLS, identifiants, client ID et codes d'état PubSubClient.

Liste de contrôle de débogage à côté d'une carte ESP32 montrant pourquoi l'ESP32 ne se connecte pas au broker MQTT
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

Quand votre ESP32 ne se connecte pas à un broker MQTT, la cause est presque toujours l'un d'une douzaine de problèmes prévisibles, de la mauvaise bande Wi-Fi à un client TLS sur un port en clair. Ce guide vous donne un ordre de vérification méthodique, explique la signification de chaque code d'erreur PubSubClient et montre comment valider chaque correction avec broker.connectmq.com.

Commencez par le code d'erreur

Avant de modifier quoi que ce soit, déterminez où la connexion échoue. PubSubClient expose la raison via client.state(). Affichez-la chaque fois que connect() renvoie false :

if (!mqtt.connect(clientId.c_str())) {
  Serial.printf("MQTT connect failed, state=%d\n", mqtt.state());
}
state() Constante Ce que cela signifie généralement
-4 MQTT_CONNECTION_TIMEOUT Le serveur n'a pas répondu dans le délai de keepalive
-3 MQTT_CONNECTION_LOST La connexion est tombée après avoir été établie
-2 MQTT_CONNECT_FAILED La connexion TCP ou TLS n'a pas pu être ouverte du tout
-1 MQTT_DISCONNECTED Le client est proprement déconnecté
1 MQTT_CONNECT_BAD_PROTOCOL Le broker n'accepte pas la version du protocole
2 MQTT_CONNECT_BAD_CLIENT_ID Client ID refusé
3 MQTT_CONNECT_UNAVAILABLE Broker indisponible
4 MQTT_CONNECT_BAD_CREDENTIALS Nom d'utilisateur ou mot de passe incorrect
5 MQTT_CONNECT_UNAUTHORIZED Client non autorisé

Cette répartition est utile : les codes négatifs signifient que le problème se situe sous MQTT (réseau, DNS, TCP, TLS), les codes positifs que le broker a répondu et vous a refusé. Un -2 vous renvoie aux solutions 1 à 6, un 4 ou un 5 aux solutions 7 à 9.

Prouvez d'abord que le côté broker fonctionne

Écartez le broker avant de toucher au firmware. Depuis un ordinateur du même réseau, lancez :

mosquitto_sub -h broker.connectmq.com -p 1883 -i pc-test-4821 -t 'connectmq/demo/4821/#' -v

Dans un second terminal :

mosquitto_pub -h broker.connectmq.com -p 1883 -i pc-pub-4821 -t connectmq/demo/4821/hello -m test

Si le message arrive, le broker et le chemin Internet fonctionnent, et le problème vient de l'ESP32 ou de son segment réseau. S'il n'arrive pas non plus sur votre ordinateur, vérifiez d'abord le pare-feu de votre réseau. La page du serveur MQTT public gratuit liste les ports et les limites sur lesquels vous pouvez tester.

Solutions au niveau réseau (codes d'état négatifs)

1. Vérifiez que le Wi-Fi est réellement connecté en 2,4 GHz

L'ESP32 (hormis les variantes récentes compatibles 5 GHz) ne dialogue qu'avec les réseaux 2,4 GHz. Un routeur bi-bande avec un seul SSID pour les deux bandes fonctionne généralement, mais un SSID uniquement en 5 GHz ne fonctionnera jamais. Vérifiez aussi l'ordre des opérations : appeler mqtt.connect() avant que WiFi.status() == WL_CONNECTED échoue toujours avec -2. Affichez WiFi.localIP() et WiFi.RSSI() ; un signal plus faible qu'environ -80 dBm provoque des échecs intermittents qui ressemblent à des problèmes de broker.

2. Vérifiez la résolution DNS

Si le nom d'hôte ne se résout pas, la connexion TCP ne démarre jamais. Testez-la directement :

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

Un échec ici désigne le serveur DNS fourni par le DHCP ou une configuration d'IP statique sans entrée DNS. Lorsque vous utilisez WiFi.config() pour une adresse statique, passez aussi la passerelle et un serveur DNS.

3. Associez le port à la bonne classe de client

C'est de loin l'erreur la plus fréquente. WiFiClient parle TCP en clair et doit utiliser le port 1883. WiFiClientSecure parle TLS et doit utiliser le port 8883. Les mélanger produit un -2 ou un -4 sans autre indice.

Classe de client Port Transport
WiFiClient 1883 MQTT en clair sur TCP
WiFiClientSecure 8883 MQTT sur TLS
Bibliothèques WebSocket 8083 / 8084 (chemin /mqtt) MQTT sur WebSocket / WebSocket sécurisé

PubSubClient ne parle pas WebSocket : les ports 8083 et 8084 sont donc réservés aux clients navigateur et aux bibliothèques compatibles WebSocket.

4. Corrigez la validation du certificat TLS

Avec WiFiClientSecure, un certificat de CA absent ou erroné fait échouer le handshake sans bruit. ConnectMQ utilise un certificat Let's Encrypt : chargez donc la racine ISRG Root X1 avec setCACert(). Pour confirmer que le TLS est en cause, appelez temporairement secureClient.setInsecure() : si la connexion fonctionne soudain, votre CA est mauvaise. Ne livrez pas setInsecure() en production. Lisez l'erreur TLS avec secureClient.lastError(buf, sizeof(buf)) pour obtenir des détails, et consultez ESP32 MQTT sur SSL/TLS pour une configuration sécurisée complète.

5. Donnez au TLS assez de mémoire et de temps

Les handshakes TLS nécessitent des dizaines de kilo-octets de heap. Si votre sketch alloue de gros tampons, des données d'image ou plusieurs clients sécurisés, le handshake échoue avec -2. Affichez ESP.getFreeHeap() juste avant la connexion. Vérifiez aussi l'horloge : la validation des certificats compare des dates, et certaines bibliothèques exigent une heure valide. Synchroniser NTP avec configTime() avant la connexion évite toute une catégorie d'échecs déroutants.

6. Vérifiez que le chemin réseau ne bloque pas les ports

Les Wi-Fi invités, les réseaux d'entreprise et certains points d'accès mobiles bloquent le 1883 ou le 8883 en sortie. Si le test sur ordinateur ci-dessus n'a fonctionné que depuis un autre réseau, essayez l'ESP32 sur un partage de connexion de téléphone. S'il s'y connecte, le réseau d'origine filtre les ports MQTT et vous devez demander à l'administrateur réseau de les ouvrir.

Solutions au niveau broker (codes d'état positifs)

7. Utilisez un client ID non vide et unique

Chaque client a besoin de son propre client ID. Deux appareils flashés avec le même ID codé en dur s'éjecteront mutuellement du broker à répétition, ce qui ressemble à des déconnexions aléatoires avec l'état -3. Un client ID vide est aussi refusé par de nombreux brokers, dont la zone publique de broker.connectmq.com. Dérivez l'ID de l'adresse MAC de la puce :

String clientId = "esp32-" + String((uint32_t)ESP.getEfuseMac(), HEX);

8. Utilisez exactement les identifiants et le client ID du portail

Sur un broker ConnectMQ privé, le client ID est lié aux identifiants émis. Si vous inventez votre propre client ID tout en utilisant le nom d'utilisateur et le mot de passe générés, le broker rejette la connexion avec le code 5, même si le mot de passe est correct. Copiez les trois valeurs depuis le portail : YOUR_CLIENT_ID, YOUR_USERNAME, YOUR_PASSWORD. Méfiez-vous des espaces invisibles en fin de chaîne lors du collage dans le code.

9. Stoppez les tempêtes de tentatives avant d'être bloqué

Une boucle de reconnexion sans délai peut bombarder le broker de nombreuses tentatives de connexion par seconde. Avec de mauvais identifiants, c'est particulièrement nuisible, car ConnectMQ bloque les adresses IP après des échecs d'authentification répétés dans le cadre de sa protection contre le flood. Espacez les tentatives et augmentez le délai après chaque échec :

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);
  }
}

Cette structure non bloquante garde aussi loop() réactive. Le guide de reconnexion MQTT ESP32 approfondit la logique de reconnexion robuste.

Solutions pour les connexions qui tombent après s'être établies

10. Appelez mqtt.loop() assez souvent

PubSubClient n'envoie les pings de keepalive et ne lit les paquets entrants qu'à l'intérieur de loop(). Un long delay() ou une lecture de capteur bloquante plus longue que l'intervalle de keepalive (15 secondes par défaut) fait croire au broker que le client est mort, et vous voyez -3 ou -4. Remplacez les longs délais par des minuteries millis(), ou augmentez le keepalive avec mqtt.setKeepAlive(30). Si la carte redémarre aussi, lisez l'article sur les resets du task watchdog ESP32 dans les projets MQTT.

11. Agrandissez le tampon pour les gros messages

Le tampon de paquets par défaut de PubSubClient fait 256 octets, topic et en-tête compris. Une publication plus grande échoue sans bruit : publish() renvoie false, et un message entrant trop grand est ignoré. Appelez mqtt.setBufferSize(1024) avant la connexion, en le dimensionnant pour votre plus gros message.

12. Respectez les limites du serveur MQTT public gratuit

La zone publique de broker.connectmq.com autorise 64 Ko par message, 10 messages par seconde et par client, 10 abonnements par client et jusqu'à 8 niveaux de topic. Un sketch qui publie dans une boucle serrée ou s'abonne à de nombreux topics peut être déconnecté pour les avoir dépassées. Limitez le rythme de publication, utilisez un seul abonnement avec wildcard plutôt que de nombreux abonnements individuels, et gardez des topics courts comme connectmq/demo/4821/room/temp.

Un sketch de diagnostic

Flashez-le quand vous êtes bloqué. Il rend compte de chaque étape séparément, pour que vous voyiez exactement où la chaîne casse :

#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(); }

Laissez mosquitto_sub tourner sur connectmq/demo/4821/# et vous verrez le message de diagnostic dès que tout fonctionne.

Quand ça marche sur le broker de test mais pas en production

La plupart des échecs en production se résument aux solutions 3, 4 et 8 : passer au port 8883 sans passer à WiFiClientSecure, oublier le certificat de CA, ou utiliser un client ID maison avec des identifiants du portail. Changez une seule chose à la fois et continuez d'afficher le code d'erreur. Le tutoriel IoT ESP32 présente un projet complet qui se connecte proprement dans les deux modes, et ce que fait un broker MQTT explique pourquoi le broker refuse certaines connexions.

Mettez votre ESP32 en ligne avec ConnectMQ

Une fois que l'appareil se connecte au broker de test, migrez-le vers un broker privé avec l'offre gratuite Serverless sur app.connectmq.com, sans carte bancaire. Le client MQTT intégré au navigateur et l'explorateur de topics en direct du portail permettent de confirmer facilement le trafic côté appareil comme côté serveur. ConnectMQ est un broker MQTT managé avec le TLS sur 8883 prêt à l'emploi : le seul certificat dont vous avez besoin sur l'ESP32 est la racine publique Let's Encrypt.

Questions fréquentes

Que signifie PubSubClient rc=-2 ?

Cela signifie que la connexion TCP ou TLS n'a pas pu être ouverte : le broker n'a donc jamais vu de paquet MQTT. Vérifiez le Wi-Fi, le DNS, la combinaison port et classe de client, le certificat de CA et le heap libre.

Pourquoi mon ESP32 se connecte-t-il puis se déconnecte-t-il toutes les quelques secondes ?

Généralement, un autre appareil utilise le même client ID, ou mqtt.loop() n'est pas appelée assez souvent pour envoyer les pings de keepalive. Donnez à chaque appareil un ID unique et supprimez les longs délais bloquants.

Puis-je utiliser le port 8083 ou 8084 avec PubSubClient ?

Non. Ce sont des ports WebSocket, et PubSubClient ne parle MQTT que sur TCP brut ou TLS. Utilisez 1883 avec WiFiClient ou 8883 avec WiFiClientSecure.

Pourquoi mes identifiants sont-ils refusés alors que le mot de passe est correct ?

Sur un broker privé avec des identifiants émis, le client ID leur est lié. Utilisez exactement le client ID affiché dans le portail avec le nom d'utilisateur et le mot de passe générés.

Articles liés

Exemple MQTT ESP-IDF : construire un client esp-mqtt à partir de zéro

Construisez un projet ESP-IDF à partir d'un dossier vide avec le composant esp-mqtt : configuration du Wi-Fi en mode station, gestionnaire d'événements MQTT, publication et abonnement, propriétés MQTT 5 et TLS avec le bundle de certificats.

9 min de lecture

Horodatage NTP ESP32 MQTT : ajouter une heure précise à chaque message

Synchronisez l'horloge de l'ESP32 avec NTP, formatez des horodatages ISO 8601 et epoch en millisecondes, et joignez-les aux payloads MQTT pour que les mesures conservent leur véritable heure de capture même lorsqu'elles sont publiées en retard.

8 min de lecture

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.