Skip to content
Tutorial
16 min read
October 17, 2026

Non-Blocking MQTT Auto-Reconnect on ESP32

Make an ESP32 MQTT client recover from Wi-Fi and broker outages without long delay() calls. Use millis()-based retry scheduling, capped backoff, unique client IDs, resubscription after reconnect and local work that continues while offline.

Non-Blocking MQTT Auto-Reconnect on ESP32

An ESP32 that connects to MQTT once during startup is easy to demonstrate and easy to break. The router may reboot, the broker may restart, Wi-Fi coverage may fluctuate or the server may be temporarily unavailable. If firmware assumes the connection will never drop, sensor reporting and remote control can stop until someone manually resets the board.

This guide shows a reconnect pattern for Arduino-style ESP32 firmware using PubSubClient. It schedules retries with millis() instead of long blocking delays, increases the wait after repeated failures, resets the retry interval after success and re-subscribes to command topics each time a new MQTT session is established.

No reconnect strategy makes an unstable network reliable by itself. It should make failure recoverable while the device continues local responsibilities and reports availability honestly.

Image pending: Image placeholder: MQTT connection state diagram showing Wi-Fi unavailable, Wi-Fi connected, broker retry with backoff, MQTT connected, subscriptions restored and telemetry resumed.

Design principles before code

  1. Keep retry timing separate from application work. Use unsigned millisecond arithmetic so wraparound is handled safely for short intervals.
  2. Do not spin in a tight loop. A disconnected broker should not consume all CPU time.
  3. Back off after repeated failure. Repeated network failures should not cause continuous reconnect traffic.
  4. Re-subscribe after reconnect. Treat subscriptions as a session-setup step unless your chosen client/session design guarantees otherwise.
  5. Use a unique client ID. Duplicate IDs can force another connection off the broker.
  6. Continue local work. Read sensors, enforce local limits and maintain safe hardware behavior when cloud messaging is down.

The example assumes PubSubClient and a broker reachable via plain MQTT for a controlled lab. Configure authentication and TLS as appropriate for the deployment; this is not a production security configuration by itself.

Hardware and library assumptions

Use an ESP32 development board, a Wi-Fi network, a reachable MQTT broker and the PubSubClient Arduino library. Add the library through Arduino IDE's Library Manager and confirm the API documented for your installed library. Configure a private SSID, Wi-Fi password, broker host, broker port and unique client ID locally.

Do not use 127.0.0.1 as the broker address in the ESP32 sketch. Use the LAN hostname/IP the board can route to. The broker must also be configured to accept that remote connection.

Image pending: Image placeholder: ESP32 connected to a router and separate Raspberry Pi/Mosquitto broker. Label the broker LAN address as a configuration value, not a fixed public IP.

1. Reconnect scheduling pattern

The example uses a single loop to manage retry timing. The MQTT library's client.loop() must be called regularly while connected so it can process traffic and keep the session alive.

This is a reconnect skeleton. Fill configuration placeholders locally, add application-specific telemetry/command behavior, and test on your installed ESP32 core and PubSubClient version.

C++

Important configuration note: this is a reconnect skeleton, not a complete secure product sketch. For a real deployment, configure broker authentication and TLS as supported by your client, protect credentials, choose safe behavior while offline, and test Wi-Fi recovery on the actual board/core version.

Image pending: Image placeholder: well-formatted Arduino IDE view of retry-state variables and the millis-based reconnect branch. Blur Wi-Fi credentials.

2. Why the retry interval grows

After an unsuccessful attempt, the interval doubles until it reaches a configured ceiling. This capped backoff reduces repeated connection attempts when the broker is offline while still retrying periodically. If the broker returns, the next successful connection resets the interval so future recovery is prompt.

A fixed retry interval can also be acceptable for a small lab, but avoid a zero-delay loop. For fleets of devices, add random jitter so many clients do not retry at exactly the same instant after a shared outage. Choose limits based on how quickly the system needs to recover and how much reconnect traffic the broker can handle.

Image pending: Image placeholder: timeline graphic showing 1s, 2s, 4s, 8s and capped 30s retry intervals, then reset after the broker reconnects.

3. Restore subscriptions and application state

When mqtt.connect succeeds, re-subscribe to each command or configuration topic the device needs. Check the return value if your library provides one, and publish status only after the session is usable. If using Last Will, configure it as part of the connect call so the broker can publish offline status after an unexpected loss.

Be careful with retained commands. A reconnect may deliver old retained data immediately after subscribing. Use retained state or desired configuration only when replaying it is intentional; do not accidentally retain a one-shot toggle or unlock command. Validate commands that affect physical outputs and, when appropriate, acknowledge with a separate reported-state publication.

4. Availability, Last Will and retained status

A common pattern is a retained online status after a successful connection and an LWT offline status registered at connect time. A dashboard can use that signal to distinguish a sensor reading still valid from one produced by a device that has vanished.

Availability status is not a substitute for last-seen timestamps. A broker may wait for the client's keep-alive timeout before publishing its Last Will. If the dashboard needs data freshness, track the time of the last valid reading separately and define a project-appropriate stale threshold.

Image pending: Image placeholder: dashboard status panel showing online/offline state and last-seen time separately from the most recent temperature reading.

5. Test failure cases, not just startup

  1. Boot with the broker offline, then start Mosquitto and confirm eventual connection.
  2. Connect successfully, stop the broker, and confirm local firmware continues to run.
  3. Restart the broker and confirm subscriptions are restored.
  4. Restart Wi-Fi or move the board out of coverage and return it.
  5. Connect another client with the same ID in a lab to understand why uniqueness matters.
  6. Inspect broker logs and the PubSubClient state value when a connection fails.
  7. Verify outputs do not unexpectedly change when retained topics are delivered.

Record results and exact library/core versions during development. Do not claim recovery-time or uptime guarantees without measuring them on the intended network and hardware. The current Arduino-ESP32 Wi-Fi API documentation describes connection and auto-reconnect behavior.

Image pending: Image placeholder: test matrix for broker outage, Wi-Fi outage, broker restart, duplicate client ID and re-subscription, with pass/fail and observed recovery time columns.

Frequently asked questions

Can I use a long delay between retries? It also delays sensing and other work placed in the loop. A scheduled retry is easier to integrate into a responsive device.

Is rc=-2 always a broker error? In PubSubClient it indicates a failed connection attempt; inspect network reachability, listener configuration and logs to find the root cause.

Should I reconnect on every loop iteration? No. Use a retry timer and backoff.

Do I need to subscribe again after reconnecting? With common client patterns, yes—treat subscriptions as part of session setup unless your persistent-session implementation explicitly provides otherwise.

Does reconnect logic make a device safe? No. Safety behavior while disconnected, power-up state and local interlocks must be designed separately.

Next steps

First configure the broker correctly with Install Mosquitto on Raspberry Pi 5, then use MQTT Troubleshooting: Connection Refused, rc=-2 and rc=5 when diagnosing a failed session.

A robust MQTT client is not one that never disconnects. It is one that recovers predictably, avoids flooding the broker, restores subscriptions, reports status honestly and keeps essential local behavior running while connectivity is unavailable.

Signal In

Built from what makers search for

The lookups piling up in SolderHub's search bar every day shape what we publish next — new component pages, board guides, and firmware notes, sent out as they go live.

By subscribing you agree to our Privacy Policy. Unsubscribe anytime.