ESP32 e Arduino

ESP32 Não Conecta ao Broker MQTT: 12 Soluções que Realmente Funcionam

Um guia sistemático de solução de problemas para quando o seu ESP32 não conecta a um broker MQTT, cobrindo Wi-Fi, DNS, portas, certificados TLS, credenciais, client IDs e códigos de estado do PubSubClient.

Checklist de depuração ao lado de uma placa ESP32 mostrando por que o ESP32 não conecta ao broker MQTT
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

Quando o seu ESP32 não conecta a um broker MQTT, a causa quase sempre é um de uma dúzia de problemas previsíveis, da banda de Wi-Fi errada a um cliente TLS em uma porta sem criptografia. Este guia mostra uma ordem sistemática de verificações, explica o que significa cada código de erro do PubSubClient e mostra como confirmar cada correção contra o broker.connectmq.com.

Comece pelo código de erro

Antes de mudar qualquer coisa, descubra onde a conexão falha. O PubSubClient expõe o motivo por meio de client.state(). Imprima-o toda vez que connect() retornar false:

if (!mqtt.connect(clientId.c_str())) {
  Serial.printf("MQTT connect failed, state=%d\n", mqtt.state());
}
state() Constante O que geralmente significa
-4 MQTT_CONNECTION_TIMEOUT O servidor não respondeu dentro do período de keepalive
-3 MQTT_CONNECTION_LOST A conexão caiu depois de estabelecida
-2 MQTT_CONNECT_FAILED A conexão TCP ou TLS nem chegou a ser aberta
-1 MQTT_DISCONNECTED O cliente está desconectado de forma limpa
1 MQTT_CONNECT_BAD_PROTOCOL O broker não aceita a versão do protocolo
2 MQTT_CONNECT_BAD_CLIENT_ID Client ID rejeitado
3 MQTT_CONNECT_UNAVAILABLE Broker indisponível
4 MQTT_CONNECT_BAD_CREDENTIALS Usuário ou senha incorretos
5 MQTT_CONNECT_UNAUTHORIZED Cliente não autorizado

Essa divisão é útil: códigos negativos indicam que o problema está abaixo do MQTT (rede, DNS, TCP, TLS), e códigos positivos indicam que o broker respondeu e recusou você. Um -2 leva você às soluções 1–6; um 4 ou 5, às soluções 7–9.

Primeiro, prove que o lado do broker funciona

Descarte o broker antes de mexer no firmware. Em um computador na mesma rede, execute:

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

Em um segundo terminal:

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

Se a mensagem chegar, o broker e o caminho pela internet funcionam, e o problema está no ESP32 ou no segmento de rede dele. Se ela também não chegar no computador, verifique primeiro o firewall da sua rede. A página do servidor MQTT público (gratuito) lista as portas e os limites que você pode testar.

Soluções no nível da rede (códigos de estado negativos)

1. Garanta que o Wi-Fi esteja realmente conectado em 2,4 GHz

O ESP32 (exceto variantes mais novas com suporte a 5 GHz) só conversa com redes de 2,4 GHz. Um roteador dual-band com um único SSID para as duas bandas normalmente funciona, mas um SSID só de 5 GHz nunca vai funcionar. Verifique também a ordem das operações: chamar mqtt.connect() antes de WiFi.status() == WL_CONNECTED sempre falha com -2. Imprima WiFi.localIP() e WiFi.RSSI(); um sinal mais fraco que cerca de -80 dBm leva a falhas intermitentes que parecem problemas do broker.

2. Verifique a resolução DNS

Se o hostname não resolve, a conexão TCP nunca começa. Teste diretamente:

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

Uma falha aqui aponta para o servidor DNS fornecido pelo DHCP ou para uma configuração de IP estático sem DNS. Ao usar WiFi.config() para um endereço estático, passe também o gateway e um servidor DNS.

3. Combine a porta com a classe do cliente

Este é, isoladamente, o erro mais comum. O WiFiClient fala TCP simples e deve usar a porta 1883. O WiFiClientSecure fala TLS e deve usar a porta 8883. Misturá-los produz um -2 ou um -4 sem nenhuma outra pista.

Classe do cliente Porta Transporte
WiFiClient 1883 MQTT simples sobre TCP
WiFiClientSecure 8883 MQTT sobre TLS
Bibliotecas WebSocket 8083 / 8084 (caminho /mqtt) MQTT sobre WebSocket / WebSocket seguro

O PubSubClient não fala WebSocket, então as portas 8083 e 8084 são apenas para clientes de navegador e bibliotecas com suporte a WebSocket.

4. Corrija a validação do certificado TLS

Com WiFiClientSecure, um certificado de CA ausente ou errado faz o handshake falhar silenciosamente. O ConnectMQ usa um certificado Let's Encrypt, então carregue a raiz ISRG Root X1 com setCACert(). Para confirmar que o TLS é o culpado, chame temporariamente secureClient.setInsecure(): se a conexão passar a funcionar de repente, sua CA está errada. Não leve setInsecure() para produção. Leia o erro TLS com secureClient.lastError(buf, sizeof(buf)) para obter detalhes e veja ESP32 MQTT com SSL/TLS para uma configuração segura completa.

5. Dê ao TLS memória e tempo suficientes

Handshakes TLS precisam de dezenas de kilobytes de heap. Se o seu sketch aloca buffers grandes, dados de imagem ou vários clientes seguros, o handshake falha com -2. Imprima ESP.getFreeHeap() logo antes de conectar. Verifique também o relógio: a validação do certificado compara datas, e algumas bibliotecas exigem uma hora válida. Sincronizar o NTP com configTime() antes de conectar evita toda uma classe de falhas intrigantes.

6. Verifique se há portas bloqueadas no caminho de rede

Wi-Fi de visitantes, redes corporativas e alguns hotspots móveis bloqueiam as portas 1883 ou 8883 de saída. Se o teste no computador acima só funcionou em outra rede, experimente o ESP32 em um hotspot de celular. Se ele conectar ali, a rede original está filtrando as portas MQTT e você precisa que o administrador de rede as libere.

Soluções no nível do broker (códigos de estado positivos)

7. Use um client ID não vazio e único

Todo cliente precisa do próprio client ID. Dois dispositivos gravados com o mesmo ID fixo no código vão derrubar um ao outro do broker repetidamente, o que parece desconexões aleatórias com estado -3. Um client ID vazio também é recusado por muitos brokers, incluindo o servidor MQTT público broker.connectmq.com. Derive o ID do MAC do chip:

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

8. Use exatamente as credenciais e o client ID do portal

Em um broker ConnectMQ privado, o client ID é vinculado às credenciais emitidas. Se você inventar seu próprio client ID usando o usuário e a senha gerados, o broker rejeita a conexão com o código 5, mesmo que a senha esteja correta. Copie os três valores do portal: YOUR_CLIENT_ID, YOUR_USERNAME, YOUR_PASSWORD. Atenção a espaços invisíveis no final ao colar no código.

9. Pare as tempestades de reconexão antes que você seja bloqueado

Um loop de reconexão sem atraso pode atingir o broker com várias tentativas de conexão por segundo. Com credenciais erradas isso é especialmente prejudicial, porque o ConnectMQ bloqueia endereços IP após repetidas falhas de login como parte da sua proteção contra flood. Espere entre as tentativas e aumente o atraso após cada falha:

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

A estrutura não bloqueante também mantém o loop() responsivo. O guia de reconexão MQTT no ESP32 se aprofunda em uma lógica de reconexão robusta.

Soluções para conexões que caem depois de conectar

10. Chame mqtt.loop() com frequência suficiente

O PubSubClient só envia pings de keepalive e lê os pacotes recebidos dentro de loop(). Um delay() longo ou uma leitura de sensor bloqueante maior que o intervalo de keepalive (15 segundos por padrão) faz o broker achar que o cliente morreu, e você vê -3 ou -4. Substitua delays longos por temporizadores com millis() ou aumente o keepalive com mqtt.setKeepAlive(30). Se a placa também reinicia, leia sobre resets do task watchdog do ESP32 em projetos MQTT.

11. Aumente o buffer para mensagens grandes

O buffer de pacotes padrão do PubSubClient é de 256 bytes, incluindo tópico e cabeçalho. Uma publicação maior falha em silêncio: publish() retorna false, e uma mensagem recebida grande demais é descartada. Chame mqtt.setBufferSize(1024) antes de conectar, dimensionado para a sua maior mensagem.

12. Respeite os limites do servidor MQTT público

O servidor MQTT público broker.connectmq.com permite 64 KB por mensagem, 10 mensagens por segundo por cliente, 10 inscrições por cliente e até 8 níveis de tópico. Um sketch que publica em um loop apertado ou se inscreve em muitos tópicos pode ser desconectado por excedê-los. Limite a taxa de publicação, use uma inscrição com curinga em vez de muitas individuais e mantenha tópicos como connectmq/demo/4821/room/temp curtos.

Um sketch de diagnóstico

Grave isto quando estiver travado. Ele reporta cada etapa separadamente, para que você veja exatamente onde a cadeia se rompe:

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

Mantenha o mosquitto_sub rodando em connectmq/demo/4821/# e você verá a mensagem de diagnóstico no instante em que tudo funcionar.

Quando funciona no servidor MQTT público, mas não em produção

A maioria das falhas em produção se resume às soluções 3, 4 e 8: mudar para a porta 8883 sem mudar para WiFiClientSecure, esquecer o certificado da CA ou usar um client ID inventado com credenciais do portal. Mude uma coisa de cada vez e continue imprimindo o código de erro. O tutorial de IoT com ESP32 mostra um projeto completo que conecta sem problemas nos dois modos, e o que um broker MQTT faz explica por que o broker recusa certas conexões.

Coloque seu ESP32 online com o ConnectMQ

Assim que o dispositivo conectar ao servidor MQTT público, mova-o para um broker privado no plano Serverless gratuito em app.connectmq.com, sem cartão de crédito. O cliente MQTT no navegador e o explorador de tópicos ao vivo do portal facilitam confirmar o tráfego tanto do lado do dispositivo quanto do lado do servidor. O ConnectMQ é um broker MQTT gerenciado com TLS na 8883 pronto para uso, então o único certificado de que você precisa no ESP32 é a raiz pública da Let's Encrypt.

Perguntas frequentes

O que significa rc=-2 no PubSubClient?

Significa que a conexão TCP ou TLS não pôde ser aberta, então o broker nunca viu um pacote MQTT. Verifique o Wi-Fi, o DNS, a combinação de porta e classe do cliente, o certificado da CA e o heap livre.

Por que meu ESP32 conecta e desconecta a cada poucos segundos?

Normalmente outro dispositivo está usando o mesmo client ID, ou mqtt.loop() não é chamado com frequência suficiente para enviar os pings de keepalive. Dê a cada dispositivo um ID único e remova delays longos que bloqueiam.

Posso usar as portas 8083 ou 8084 com o PubSubClient?

Não. Essas são portas WebSocket, e o PubSubClient só fala MQTT sobre TCP puro ou TLS. Use 1883 com WiFiClient ou 8883 com WiFiClientSecure.

Por que minhas credenciais são rejeitadas mesmo com a senha correta?

Em um broker privado com credenciais emitidas, o client ID é vinculado a elas. Use exatamente o client ID mostrado no portal junto com o usuário e a senha gerados.

Artigos relacionados

Exemplo de MQTT com ESP-IDF: Monte um Cliente esp-mqtt do Zero

Monte um projeto ESP-IDF a partir de uma pasta vazia com o componente esp-mqtt: configuração do Wi-Fi em modo station, o handler de eventos MQTT, publicação e inscrição, propriedades do MQTT 5 e TLS com o bundle de certificados.

8 min de leitura

Usando os Recursos do MQTT 5 do esp-mqtt no ESP32 com ESP-IDF

Um projeto ESP-IDF prático que ativa o MQTT 5.0 no esp-mqtt e usa user properties, expiração de mensagens, topic aliases, expiração de sessão e response topics com um broker MQTT 5 real.

8 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.