ESP32 and Arduino

ESP32 Cannot Connect to MQTT Broker: 12 Fixes That Actually Work

A systematic troubleshooting guide for when your ESP32 cannot connect to an MQTT broker, covering Wi-Fi, DNS, ports, TLS certificates, credentials, client IDs and PubSubClient state codes.

Debugging checklist next to an ESP32 board showing why the ESP32 cannot connect to MQTT broker
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

When your ESP32 cannot connect to an MQTT broker, the cause is almost always one of a dozen predictable problems, from the wrong Wi-Fi band to a TLS client on a plain port. This guide gives you a systematic order of checks, explains what each PubSubClient error code means and shows how to confirm every fix against broker.connectmq.com.

Start With the Error Code

Before changing anything, find out where the connection fails. PubSubClient exposes the reason through client.state(). Print it every time connect() returns false:

if (!mqtt.connect(clientId.c_str())) {
  Serial.printf("MQTT connect failed, state=%d\n", mqtt.state());
}
state() Constant What it usually means
-4 MQTT_CONNECTION_TIMEOUT Server did not answer within the keepalive period
-3 MQTT_CONNECTION_LOST Connection dropped after it was established
-2 MQTT_CONNECT_FAILED TCP or TLS connection could not be opened at all
-1 MQTT_DISCONNECTED Client is cleanly disconnected
1 MQTT_CONNECT_BAD_PROTOCOL Broker does not accept the protocol version
2 MQTT_CONNECT_BAD_CLIENT_ID Client ID rejected
3 MQTT_CONNECT_UNAVAILABLE Broker unavailable
4 MQTT_CONNECT_BAD_CREDENTIALS Wrong username or password
5 MQTT_CONNECT_UNAUTHORIZED Client not authorised

The split is useful: negative codes mean the problem is below MQTT (network, DNS, TCP, TLS), positive codes mean the broker answered and refused you. A -2 sends you to fixes 1–6, a 4 or 5 sends you to fixes 7–9.

Prove the Broker Side Works First

Rule out the broker before you touch firmware. From a computer on the same network, run:

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

In a second terminal:

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

If the message arrives, the broker and the internet path work, and the issue is on the ESP32 or its network segment. If it does not arrive from your computer either, check your network's firewall first. The public MQTT test broker page lists the ports and limits you can test against.

Network-Level Fixes (Negative State Codes)

1. Make Sure Wi-Fi Is Really Connected on 2.4 GHz

The ESP32 (except newer variants with 5 GHz support) only talks to 2.4 GHz networks. A dual-band router with one SSID for both bands usually works, but a 5 GHz-only SSID never will. Also check the order of operations: calling mqtt.connect() before WiFi.status() == WL_CONNECTED always fails with -2. Print WiFi.localIP() and WiFi.RSSI(); a signal weaker than roughly -80 dBm leads to intermittent failures that look like broker problems.

2. Check DNS Resolution

If the hostname does not resolve, the TCP connection never starts. Test it directly:

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

A failure here points at the DHCP-provided DNS server or a static IP configuration without a DNS entry. When you use WiFi.config() for a static address, pass the gateway and a DNS server too.

3. Match the Port to the Client Class

This is the single most common mistake. WiFiClient speaks plain TCP and must use port 1883. WiFiClientSecure speaks TLS and must use port 8883. Mixing them produces a -2 or a -4 with no further hint.

Client class Port Transport
WiFiClient 1883 Plain MQTT over TCP
WiFiClientSecure 8883 MQTT over TLS
WebSocket libraries 8083 / 8084 (path /mqtt) MQTT over WebSocket / secure WebSocket

PubSubClient does not speak WebSocket, so ports 8083 and 8084 are for browser clients and WebSocket-capable libraries only.

4. Fix TLS Certificate Validation

With WiFiClientSecure, a missing or wrong CA certificate causes the handshake to fail silently. ConnectMQ uses a Let's Encrypt certificate, so load the ISRG Root X1 root with setCACert(). To confirm that TLS is the culprit, temporarily call secureClient.setInsecure(): if the connection suddenly works, your CA is wrong. Do not ship setInsecure() in production. Read the TLS error with secureClient.lastError(buf, sizeof(buf)) for details, and see ESP32 MQTT over SSL/TLS for a complete secure setup.

5. Give TLS Enough Memory and Time

TLS handshakes need tens of kilobytes of heap. If your sketch allocates large buffers, image data or several secure clients, the handshake fails with -2. Print ESP.getFreeHeap() just before connecting. Also check the clock: certificate validation compares dates, and some libraries require a valid time. Syncing NTP with configTime() before connecting avoids a whole class of puzzling failures.

6. Check the Network Path for Blocked Ports

Guest Wi-Fi, corporate networks and some mobile hotspots block outbound 1883 or 8883. If the computer test above only worked from a different network, try the ESP32 on a phone hotspot. If it connects there, the original network is filtering MQTT ports and you need the network administrator to open them.

Broker-Level Fixes (Positive State Codes)

7. Use a Non-Empty, Unique Client ID

Every client needs its own client ID. Two devices flashed with the same hard-coded ID will kick each other off the broker repeatedly, which looks like random disconnects with state -3. An empty client ID is also refused by many brokers, including the public area of broker.connectmq.com. Derive the ID from the chip's MAC:

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

8. Use the Exact Credentials and Client ID From the Portal

On a private ConnectMQ broker, the client ID is bound to the issued credentials. If you invent your own client ID while using the generated username and password, the broker rejects the connection with code 5 even though the password is correct. Copy all three values from the portal: YOUR_CLIENT_ID, YOUR_USERNAME, YOUR_PASSWORD. Watch for invisible trailing spaces when pasting into code.

9. Stop Retry Storms Before They Get You Blocked

A reconnect loop without a delay can hit the broker with many connection attempts per second. With wrong credentials that is especially harmful, because ConnectMQ blocks IP addresses after repeated failed logins as part of its flood protection. Back off between attempts, and grow the delay after each failure:

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

The non-blocking structure also keeps loop() responsive. The ESP32 MQTT reconnect guide goes deeper into robust reconnection logic.

Fixes for Connections That Drop After Connecting

10. Call mqtt.loop() Often Enough

PubSubClient only sends keepalive pings and reads incoming packets inside loop(). A long delay() or a blocking sensor read longer than the keepalive interval (15 seconds by default) makes the broker think the client died, and you see -3 or -4. Replace long delays with millis() timers, or raise the keepalive with mqtt.setKeepAlive(30). If the board also resets, read about ESP32 task watchdog resets in MQTT projects.

11. Increase the Buffer for Large Messages

PubSubClient's default packet buffer is 256 bytes, including topic and header. A larger publish fails quietly: publish() returns false, and an oversized incoming message is dropped. Call mqtt.setBufferSize(1024) before connecting, sized for your largest message.

12. Respect the Public Broker Limits

The public area of broker.connectmq.com allows 64 KB per message, 10 messages per second per client, 10 subscriptions per client and up to 8 topic levels. A sketch that publishes in a tight loop or subscribes to many topics can be disconnected for exceeding them. Throttle publishing, use one wildcard subscription instead of many individual ones, and keep topics like connectmq/demo/4821/room/temp short.

A Diagnostic Sketch

Flash this when you are stuck. It reports each stage separately, so you see exactly where the chain breaks:

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

Keep mosquitto_sub running on connectmq/demo/4821/# and you will see the diagnostic message the moment everything works.

When It Works on the Test Broker but Not in Production

Most production failures come down to fixes 3, 4 and 8: switching to port 8883 without switching to WiFiClientSecure, forgetting the CA certificate, or using a self-made client ID with portal credentials. Change one thing at a time and keep the error code printing. The ESP32 IoT tutorial shows a complete project that connects cleanly in both modes, and what an MQTT broker does explains why the broker refuses certain connections.

Get Your ESP32 Online with ConnectMQ

Once the device connects to the test broker, move it to a private broker on the free Serverless plan at app.connectmq.com, with no credit card required. The portal's in-browser MQTT client and live topic explorer make it easy to confirm traffic from the device side and the server side. ConnectMQ is a managed MQTT broker with TLS on 8883 out of the box, so the only certificate you need on the ESP32 is the public Let's Encrypt root.

Frequently Asked Questions

What does PubSubClient rc=-2 mean?

It means the TCP or TLS connection could not be opened, so the broker never saw an MQTT packet. Check Wi-Fi, DNS, the port and client class combination, the CA certificate and free heap.

Why does my ESP32 connect and then disconnect every few seconds?

Usually another device is using the same client ID, or mqtt.loop() is not called often enough to send keepalive pings. Give each device a unique ID and remove long blocking delays.

Can I use port 8083 or 8084 with PubSubClient?

No. Those are WebSocket ports, and PubSubClient only speaks MQTT over raw TCP or TLS. Use 1883 with WiFiClient or 8883 with WiFiClientSecure.

Why are my credentials rejected even though the password is correct?

On a private broker with issued credentials, the client ID is bound to them. Use the exact client ID shown in the portal together with the generated username and password.

Related articles

ESP-IDF MQTT Example: Build an esp-mqtt Client from Scratch

Build an ESP-IDF project from an empty folder with the esp-mqtt component: Wi-Fi station setup, the MQTT event handler, publish and subscribe, MQTT 5 properties and TLS with the certificate bundle.

8 min read

Using esp-mqtt MQTT 5 Features on ESP32 with ESP-IDF

A hands-on ESP-IDF project that enables MQTT 5.0 in esp-mqtt and uses user properties, message expiry, topic aliases, session expiry and response topics against a real MQTT 5 broker.

7 min read

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.