Skip to content

MQTT Client Setup

MQTT Client Setup

This section covers setting up an MQTT client on the ESP32 using the PubSubClient library. By the end of this section, you will be able to:

  • Install and configure the PubSubClient library for ESP32
  • Connect the ESP32 to an MQTT broker
  • Implement connection retry logic with Wi-Fi dependency management
  • Configure MQTT server address, port, and authentication
  • ESP32 with working Wi-Fi connection (01-09)
  • A running MQTT broker (Mosquitto on the same network, default port 1883)
  • PubSubClient library installed (via Library Manager or lib_deps)

The PubSubClient library by Nick O’Leary (creator of Node-RED) is the de facto MQTT client for Arduino-compatible boards. It handles the MQTT protocol details while providing a simple API.

Key Characteristics:

  • Lightweight (~15 KB flash, ~2 KB RAM)
  • Supports QoS 0 and QoS 1
  • Supports MQTT 3.1.1
  • No built-in TLS support (requires WiFiClientSecure for TLS — see 01-16)
  • Single-threaded, must be polled in loop()

Core Functions:

FunctionDescription
PubSubClient(wifiClient)Constructor with Wi-Fi client
setServer(broker, port)Set MQTT broker address and port
setCallback(callback)Register message handler
connect(clientId)Connect to broker
connect(clientId, user, pass)Connect with authentication
publish(topic, payload)Publish a message
subscribe(topic)Subscribe to a topic
loop()Maintain connection, process messages
connected()Check MQTT connection status

Each MQTT client must have a unique client identifier (client ID). If two clients connect with the same ID, the broker will disconnect the first one. The convention is to use a device-specific name:

const char* clientId = "esp32-sensor-01";
// Or generate dynamically:
String clientId = "esp32-" + String(WiFi.macAddress());

The server configuration requires:

  • Broker IP/Hostname: e.g., "192.168.1.100" or "mqtt.local" (mDNS)
  • Port: 1883 (unencrypted) or 8883 (TLS)
  • Credentials (optional): Username and password

This example establishes an MQTT connection after Wi-Fi is connected:

#include <WiFi.h>
#include <PubSubClient.h>
// Wi-Fi credentials
const char* ssid = "YourWiFiSSID";
const char* password = "YourWiFiPassword";
// MQTT broker configuration
const char* mqttServer = "192.168.1.100"; // Your broker IP
const int mqttPort = 1883;
const char* mqttUser = ""; // Leave empty if no auth
const char* mqttPassword = "";
const char* clientId = "esp32-client";
WiFiClient wifiClient;
PubSubClient client(wifiClient);
void setup() {
Serial.begin(115200);
delay(1000);
// Connect to Wi-Fi
connectToWiFi();
// Configure MQTT
client.setServer(mqttServer, mqttPort);
client.setCallback(mqttCallback);
// Connect to MQTT broker
connectToMQTT();
}
void loop() {
// Maintain MQTT connection (must be called regularly)
if (!client.connected()) {
connectToMQTT();
}
client.loop();
// Your other code here
delay(100);
}
void connectToWiFi() {
Serial.print("Connecting to Wi-Fi");
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWi-Fi connected!");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("\nWi-Fi failed! Restarting...");
ESP.restart();
}
}
void connectToMQTT() {
// Loop until connected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect(clientId, mqttUser, mqttPassword)) {
Serial.println("connected!");
// Subscribe to topics after successful connection
client.subscribe("esp32/commands");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" retrying in 5 seconds");
delay(5000);
}
}
}
void mqttCallback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.println(topic);
String message;
for (unsigned int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.print("Message: ");
Serial.println(message);
}

Step 2: MQTT Connection with Last Will and Testament (LWT)

Section titled “Step 2: MQTT Connection with Last Will and Testament (LWT)”

LWT is a feature that sends a predefined message when a client unexpectedly disconnects:

// LWT configuration
const char* willTopic = "esp32/status";
const char* willMessage = "offline";
int willQos = 1;
bool willRetain = true;
void connectToMQTT() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Connect with LWT: (clientId, user, pass, willTopic, willQos, willRetain, willMessage)
if (client.connect(clientId, mqttUser, mqttPassword,
willTopic, willQos, willRetain, willMessage)) {
Serial.println("connected!");
// Publish online status
client.publish("esp32/status", "online", true);
// Subscribe
client.subscribe("esp32/commands");
} else {
Serial.print("failed, rc=");
Serial.println(client.state());
delay(5000);
}
}
}

Step 3: MQTT Connection with Authentication

Section titled “Step 3: MQTT Connection with Authentication”

If your broker requires authentication, pass the username and password:

const char* mqttUser = "iot-device";
const char* mqttPassword = "secure-password-123";
void connectToMQTT() {
while (!client.connected()) {
if (client.connect(clientId, mqttUser, mqttPassword)) {
Serial.println("MQTT connected with authentication");
client.subscribe("esp32/commands");
} else {
Serial.print("MQTT auth failed, state: ");
Serial.println(client.state());
delay(5000);
}
}
}

The client.state() function returns the connection state. Common values:

CodeConstantMeaning
-4MQTT_CONNECTION_TIMEOUTConnection timed out
-3MQTT_CONNECTION_LOSTConnection lost
-2MQTT_CONNECT_FAILEDConnection failed
-1MQTT_DISCONNECTEDClient disconnected
0MQTT_CONNECTEDSuccessfully connected
1MQTT_CONNECT_BAD_PROTOCOLWrong protocol version
2MQTT_CONNECT_BAD_CLIENT_IDClient ID rejected
3MQTT_CONNECT_UNAVAILABLEServer unavailable
4MQTT_CONNECT_BAD_CREDENTIALSUsername/password wrong
5MQTT_CONNECT_UNAUTHORIZEDNot authorized
  • ESP32 connects to the MQTT broker after Wi-Fi connection
  • Serial Monitor shows “MQTT connected” message
  • Subscribe to esp32/status from another client shows “online” message
  • Disconnecting ESP32 sends “offline” via LWT
  • MQTT connection with authentication succeeds (if applicable)

Common return codes and solutions:

  • rc=4: Bad credentials — check MQTT username and password
  • rc=5: Not authorized — check broker ACL settings
  • rc=-2: Network unreachable — verify broker IP and Wi-Fi connectivity
  • rc=-4: Timeout — broker may be on different network or firewall blocking port 1883

General solutions:

  1. Verify broker is running: mosquitto_sub -h 192.168.1.100 -t "test" on a computer
  2. Check firewall: Port 1883 must be open between ESP32 and broker
  3. Ping broker from ESP32 (use ping command if available)
  4. Check client ID uniqueness: No other device should use the same clientId

”WiFiClient not connected” error in MQTT

Section titled “”WiFiClient not connected” error in MQTT”

Cause: Wi-Fi disconnects before MQTT reconnection is attempted.

Solution: Always verify Wi-Fi status before MQTT operations:

void loop() {
if (WiFi.status() == WL_CONNECTED) {
if (!client.connected()) {
connectToMQTT();
}
client.loop();
} else {
// Reconnect Wi-Fi first
connectToWiFi();
}
}

Causes:

  • client.loop() not called frequently enough
  • Not subscribed to the correct topic
  • QoS mismatch between publisher and subscriber

Solutions:

  1. Ensure client.loop() is called at least every 100ms
  2. Verify subscription topic exactly matches publisher topic
  3. Try with QoS 0 for both publisher and subscriber
  • Combine Wi-Fi and MQTT reconnection: Always check Wi-Fi before attempting MQTT connection
  • Use unique client IDs: Append MAC address to client ID to avoid conflicts
  • Enable LWT: The Last Will message helps the broker (and Node-RED) detect offline devices
  • Keep client.loop() frequent: Call it in every loop() iteration, not inside long delays
  • Log connection state: Using client.state() helps diagnose connection issues
  • Set a shorter keep-alive: Default is 15 seconds; for unstable networks, reduce to 10 seconds via client.setKeepAlive(10)
  1. PubSubClient is the standard MQTT library for ESP32, configured via setServer() and setCallback()
  2. MQTT connection requires an active Wi-Fi connection — always check Wi-Fi status first
  3. Every client needs a unique ID; duplicates cause disconnections
  4. LWT (Last Will and Testament) enables offline detection
  5. client.loop() must be called frequently to maintain connection and process messages
  6. Connection return codes help diagnose authentication and network issues