Pruebas de brokers

Probar la conexión MQTT de un ESP32 paso a paso

¿Tu ESP32 no conecta a MQTT? Prueba Wi-Fi, DNS, puerto TCP, client ID, credenciales y tamaño de buffer uno a uno con un sketch de diagnóstico y logs serie.

Actualizado · 8 min de lectura

Probar la conexión MQTT de un ESP32 paso a paso

Cuando un ESP32 se niega a hablar con un broker MQTT, el monitor serie suele mostrar una única línea poco útil: failed, rc=-2 try again in 5 seconds. La forma más rápida de salir es probar la conexión capa por capa (Wi-Fi, DNS, puerto TCP, handshake MQTT y publicación) y detenerse en la primera capa que falle.

Esta guía te da un sketch de diagnóstico para el core de Arduino (core ESP32 3.x con PubSubClient 2.8) que hace exactamente eso, explica cada resultado y muestra cómo confirmar desde el lado del broker que la placa está realmente ahí.

El checklist de un vistazo

PasoQué puede fallarCómo se manifiesta
1. Log serieBaudios incorrectos, ningún logBasura o silencio en el monitor
2. Wi-FiSSID/contraseña incorrectos, red de 5 GHz, señal débilWiFi.status() nunca llega a WL_CONNECTED (3)
3. DNSDHCP sin servidor DNS, errata en el hosthostByName falla
4. Puerto TCPFirewall, puerto incorrecto, puerto TLS con cliente sin TLSrc=-2 de PubSubClient
5. MQTT CONNECTClient ID duplicado, credenciales erróneas, ACLrc=2, rc=4, rc=5
6. PublicaciónPaquete más grande que el bufferpublish() devuelve false
7. Mantener la conexiónNo se llama a loop(), keep alive demasiado cortorc=-3 al cabo de un rato

Paso 1: consigue un log serie legible

Configura el monitor a la misma velocidad que Serial.begin(); 115200 es lo habitual. En el Arduino IDE, pon también Tools → Core Debug Level en Info o Verbose: así el core del ESP32 imprime los eventos de Wi-Fi y los errores TLS que tu sketch nunca ve. En PlatformIO, usa monitor_speed = 115200 y build_flags = -DCORE_DEBUG_LEVEL=4.

Pasos 2–6: el sketch de diagnóstico

Flashea este sketch antes de tocar tu firmware real. Comprueba cada capa en orden e imprime exactamente dónde se detiene.

esp32_mqtt_check.ino
#include <WiFi.h>
#include <PubSubClient.h>

const char* WIFI_SSID = "your-ssid";
const char* WIFI_PASS = "your-wifi-password";
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* MQTT_USER = "username";   // nullptr si el broker permite acceso anónimo
const char* MQTT_PASS = "password";

WiFiClient net;
PubSubClient mqtt(net);
String clientId;

bool check() {
  Serial.println("\n[1] Wi-Fi");
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  unsigned long t0 = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - t0 < 20000) { delay(250); Serial.print('.'); }
  if (WiFi.status() != WL_CONNECTED) {
    Serial.printf("\nWi-Fi failed, status=%d\n", WiFi.status());
    return false;
  }
  Serial.printf("\nIP %s  gateway %s  RSSI %d dBm\n", WiFi.localIP().toString().c_str(),
                WiFi.gatewayIP().toString().c_str(), WiFi.RSSI());

  Serial.println("[2] DNS");
  IPAddress ip;
  if (!WiFi.hostByName(MQTT_HOST, ip)) { Serial.println("DNS lookup failed"); return false; }
  Serial.printf("%s -> %s\n", MQTT_HOST, ip.toString().c_str());

  Serial.println("[3] TCP port");
  if (!net.connect(ip, MQTT_PORT)) { Serial.println("TCP connect failed"); return false; }
  Serial.println("TCP OK");
  net.stop();

  Serial.println("[4] MQTT CONNECT");
  clientId = "esp32-" + WiFi.macAddress();
  clientId.replace(":", "");
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  mqtt.setBufferSize(1024);
  mqtt.setKeepAlive(30);
  if (!mqtt.connect(clientId.c_str(), MQTT_USER, MQTT_PASS)) {
    Serial.printf("MQTT failed, rc=%d\n", mqtt.state());
    return false;
  }
  Serial.printf("MQTT OK as %s\n", clientId.c_str());

  Serial.println("[5] PUBLISH");
  String topic = "testmqtt/esp32-check/" + clientId + "/hello";
  bool ok = mqtt.publish(topic.c_str(), "ESP32 connection test passed");
  Serial.printf("publish to %s: %s\n", topic.c_str(), ok ? "OK" : "FAILED");
  return ok;
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println(check() ? "\nALL CHECKS PASSED" : "\nCHECK FAILED - see the last step above");
}

void loop() {
  mqtt.loop();
}

Interpretar los resultados

Códigos de estado del Wi-Fi

statusSignificadoSolución
1 WL_NO_SSID_AVAILRed no encontradaRevisa cómo está escrito el SSID; asegúrate de que emite en 2,4 GHz
4 WL_CONNECT_FAILEDRechazado, normalmente contraseña incorrectaVuelve a escribir la contraseña; las redes solo WPA3 pueden necesitar el modo mixto WPA2/WPA3
6 WL_DISCONNECTEDSigue intentándolo o se cayóAcércate; un RSSI por debajo de unos -80 dBm no es fiable

Un buen RSSI está más o menos entre -50 y -70 dBm. Si el Wi-Fi conecta pero se cae después, consulta desconexiones de Wi-Fi y MQTT en el ESP32.

DNS y TCP

DNS lookup failed significa que la placa no recibió un servidor DNS utilizable por DHCP o que el nombre del host está mal. Comprueba el mismo nombre desde un portátil en la misma red con nslookup broker.connectmq.com. Como prueba temporal puedes conectar por IP, pero no lo dejes así en producción.

TCP connect failed (y rc=-2 en tu propio firmware) significa que nada respondió en ese host y puerto. Causas comunes: una red de invitados o un firewall corporativo que bloquea el 1883, una errata en el puerto o usar el puerto 8883 con un WiFiClient normal; los puertos TLS necesitan WiFiClientSecure y un certificado de CA, como se muestra en MQTT sobre TLS con ESP32. Confírmalo desde un portátil en el mismo Wi-Fi con nc -vz broker.connectmq.com 1883.

Códigos de retorno de PubSubClient

rcConstanteCausa habitual
-4MQTT_CONNECTION_TIMEOUTNo llegó el CONNACK a tiempo o expiró el keep alive
-3MQTT_CONNECTION_LOSTSe perdió la conexión; no se llama a loop() con suficiente frecuencia
-2MQTT_CONNECT_FAILEDFalló la conexión TCP (ver arriba)
-1MQTT_DISCONNECTEDDesconexión limpia / nunca conectado
1MQTT_CONNECT_BAD_PROTOCOLEl broker no acepta MQTT 3.1.1
2MQTT_CONNECT_BAD_CLIENT_IDClient ID rechazado (vacío, demasiado largo, caracteres no válidos)
3MQTT_CONNECT_UNAVAILABLEBroker no disponible
4MQTT_CONNECT_BAD_CREDENTIALSUsuario o contraseña incorrectos
5MQTT_CONNECT_UNAUTHORIZEDNo autorizado: faltan credenciales o el cliente no tiene permiso

Los valores positivos son la respuesta CONNACK del propio broker, así que la red está bien y solo queda la configuración. La referencia de reason codes muestra los códigos MQTT equivalentes, y PubSubClient no conecta profundiza en cada uno.

publish() devuelve false

El buffer por defecto de PubSubClient es de 256 bytes y debe contener el paquete completo: cabecera, topic y payload. Un payload JSON de 200 bytes en un topic largo ya lo supera, y publish() simplemente devuelve false sin que llegue nada al broker. Llama a setBufferSize() antes de conectar; la calculadora de tamaño de paquete te dice lo grande que es realmente un paquete.

Paso 7: mantener la conexión

mqtt.loop() debe ejecutarse a menudo, al menos varias veces por intervalo de keep alive. Un delay(60000) en loop() o una lectura de sensor bloqueante garantizan un rc=-3 tras aproximadamente un periodo y medio de keep alive, porque el broker nunca recibe un PINGREQ. Sustituye los delays largos por temporizadores con millis() y reconecta con backoff en lugar de bloquear en un bucle while (!mqtt.connected()).

Confírmalo desde el lado del broker

Una línea serie que dice "OK" es la opinión del dispositivo. Verifícalo de forma independiente: abre el cliente MQTT online, conéctate al mismo broker y suscríbete a testmqtt/esp32-check/#. Reinicia la placa y deberías ver llegar el mensaje hello en pocos segundos. Desde una terminal, la misma comprobación es:

Esperar el mensaje de prueba del ESP32
mosquitto_sub -h broker.connectmq.com -p 1883 \
  -u "$MQTT_USER" -P "$MQTT_PASS" \
  -t 'testmqtt/esp32-check/#' -v

Espera a tu ESP32 en el navegador

La mayoría de los problemas MQTT del ESP32 no son problemas de MQTT: son problemas de Wi-Fi, DNS o puertos escondidos tras un único código de retorno. Prueba una capa cada vez, lee el valor exacto de status o rc y confírmalo en el lado del broker antes de pasar a tu firmware real. Para la configuración completa con Arduino, continúa con MQTT en ESP32 con Arduino.

Preguntas frecuentes

¿Qué significa "failed, rc=-2" en un ESP32?

Es MQTT_CONNECT_FAILED de PubSubClient: no se pudo abrir la conexión TCP con el broker. La causa está por debajo de MQTT: sin Wi-Fi, host o puerto incorrectos, fallo de DNS, un firewall o un puerto TLS usado con un WiFiClient normal.

¿Por qué mi ESP32 conecta pero publish() devuelve false?

Casi siempre el mensaje es más grande que el buffer de PubSubClient, que por defecto es de 256 bytes incluyendo topic y cabecera. Llama a setBufferSize(1024) o más antes de conectar y comprueba el valor de retorno de cada publish.

¿El ESP32 admite Wi-Fi de 5 GHz para MQTT?

El ESP32 clásico, el S2, el S3 y el C3 solo tienen radio de 2,4 GHz, así que no pueden unirse a una red solo de 5 GHz. Chips más nuevos como el ESP32-C5 son de doble banda. Comprueba tu módulo exacto antes de depurar MQTT.