MQTT on ESP32: A Beginner's Guide

Introduction
If you are looking for a beginner-friendly guide to connect ESP32 to MQTT, this tutorial will walk you through a complete working example using Arduino IDE.
You will learn how to:
- Connect ESP32 to Wi-Fi
- Set up MQTT client using PubSubClient
- Publish and subscribe to MQTT topics
- Test communication using MQTTX or a public broker
What is MQTT and Why Use it on ESP32?
MQTT is a lightweight messaging protocol for IoT in publish/subscribe model, offering reliable real-time communication with minimal code and bandwidth overhead. It is especially beneficial for devices with limited resources and low-bandwidth networks, making it widely adopted in IoT, mobile internet, IoV, and power industries.
ESP32, an upgraded version of ESP8266, is a low-cost, low-power system on a chip microcontroller. In addition to the Wi-Fi module, the ESP32 also includes a Bluetooth 4.0 module. The dual-core CPU operates at a frequency of 80 to 240 MHz. It contains two Wi-Fi and Bluetooth modules and various input and output pins. ESP32 is an ideal choice for IoT projects.
Why MQTT + ESP32 is a Popular IoT Stack
Using MQTT on ESP32 offers several advantages:
- First, MQTT is a lightweight messaging protocol optimized for constrained devices and networks like ESP32 and Wi-Fi, so it has minimal impact on power and bandwidth.
- Second, MQTT supports different levels of reliability and quality of service to match the capabilities of ESP32. This flexibility makes it suitable for use even when networks are unstable.
- Third, ESP32 and MQTT are widely used in IoT applications, allowing them to be well integrated into IoT solutions. The MQTT protocol is also designed to simplify integration with cloud platforms to enable device control and data monitoring across networks.
Overall, the combination of ESP32 and MQTT is ideal for IoT applications that require wireless connectivity and efficient messaging between many devices. This blog will show you the process of publishing MQTT messages and topic subscription on ESP32 using Arduino IDE through a simple demo.
Prepare an MQTT Broker
Before proceeding, please ensure you have an MQTT broker to communicate and test with. We recommend you use EMQX Platform Serverless Plan.
EMQX Cloud is a comprehensive, fully-managed MQTT messaging cloud service that seamlessly connects your IoT devices to any cloud without the hassle of infrastructure maintenance. The Serverless Plan provides MQTT services on a secure, scalable cluster with pay-as-you-go pricing, making it a flexible and cost-effective solution for starting with MQTT.
This article will use the free public MQTT broker to simplify the process:
- Server:
broker.emqx.io - TCP Port:
1883 - WebSocket Port:
8083 - SSL/TLS Port:
8883 - Secure WebSocket Port:
8084
Getting Started with MQTT on ESP32
MQTT on ESP32 in 5 Minutes (Quick Overview)
If you just want to get MQTT working on ESP32 quickly, here is the minimal flow:
- Install ESP32 board support in Arduino IDE
- Install PubSubClient library
- Connect ESP32 to Wi-Fi
- Connect to MQTT broker (
broker.emqx.io) - Publish and subscribe to a test topic (
emqx/esp32) - Print messages via Serial Monitor
That's it — once connected, ESP32 can:
- Publish sensor data to MQTT broker
- Receive commands from MQTT clients like MQTTX
- Build full IoT communication pipelines
The rest of this guide explains each step in detail.
Arduino Configuration
Arduino is an open-source electronics platform based on easy-to-use hardware and software. It is intended for anyone making interactive projects. Arduino boards can read inputs - a light on a sensor, a finger on a button, or a Twitter message - and turn them into an output - activating a motor, turning on an LED, or publishing something online.
In this project, we will use an Arduino board to connect the ESP32 module to our computer. The Arduino will handle uploading code to the ESP32 and provide a serial connection between the ESP32 and our laptop.
Please refer to the official Arduino documentation for detailed instructions on installing Arduino.
Install ESP32 Development Board
The ESP32 development board is crucial in working with MQTT on the ESP32 platform. It provides hardware and software support for developing and deploying MQTT-based projects on the ESP32. With its integrated Wi-Fi and Bluetooth capabilities, GPIO pins for interfacing with external components, and compatibility with the Arduino IDE, the ESP32 development board enables seamless connectivity, prototyping, and testing of MQTT-based IoT applications.
These steps will guide you through installing the ESP32 development board in the Arduino IDE:
- Click on "Tools" in the Arduino IDE menu.
- Select "Development Board" and then choose "Development Board Management".
- In the Boards Manager, search for "ESP32".
- Once found, click on it and then click the "Install" button.

Install PubSubClient
Next, we will proceed to install the MQTT client library PubSubClient. Developed by Nick O'Leary, PubSubClient is a lightweight MQTT client library designed for Arduino-based projects. It provides a client for simple publish/subscribe messaging with a server supporting MQTT. This library simplifies MQTT communication and enables efficient data exchange in Arduino-based IoT applications.
To install the PubSubClient library, please follow these steps:
- Open the Arduino IDE, then go to "Project" in the menu bar.
- Select "Load library" and then choose "Library manager".
- In the Library Manager, type "PubSubClient" into the search bar.
- Locate the "PubSubClient" library by Nick O'Leary and click the "Install" button.

By following these steps, you will successfully install the PubSubClient library into your Arduino IDE.
Create an MQTT Connection
TCP Connection
- First, we need to import the WiFi and PubSubClient libraries. The WiFi library allows ESP32 to establish connections with Wi-Fi networks, while the PubSubClient library enables ESP32 to connect to an MQTT broker for publishing messages and subscribing to topics.
#include <WiFi.h> #include <PubSubClient.h> - Please configure the following parameters: Wi-Fi network name and password, MQTT broker address and port, and the topic to
emqx/esp32.// WiFi const char *ssid = "xxxxx"; // Enter your WiFi name const char *password = "xxxxx"; // Enter WiFi password // MQTT Broker const char *mqtt_broker = "broker.emqx.io"; const char *topic = "emqx/esp32"; const char *mqtt_username = "emqx"; const char *mqtt_password = "public"; const int mqtt_port = 1883; - Open a serial connection to display program results and establish a connection to the Wi-Fi network.
// Set software serial baud to 115200; Serial.begin(115200); // Connecting to a Wi-Fi network WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.println("Connecting to WiFi.."); } - Utilize PubSubClient to establish a connection with the MQTT broker.
client.setServer(mqtt_broker, mqtt_port); client.setCallback(callback); while (!client.connected()) { String client_id = "esp32-client-"; client_id += String(WiFi.macAddress()); Serial.printf("The client %s connects to the public MQTT broker\n", client_id.c_str()); if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) { Serial.println("Public EMQX MQTT broker connected"); } else { Serial.print("failed with state "); Serial.print(client.state()); delay(2000); } }
TLS/SSL
Implementing MQTT TLS/SSL encryption ensures end-to-end data confidentiality and prevents sniffing or tampering in untrusted public networks.
This ESP32 code establishes a secure Wi-Fi connection using a server root CA certificate. The ca_cert variable contains the root CA certificate in PEM format. The espClient object is configured with the server root CA certificate using the setCACert() function. This setup enables the ESP32 client to verify the server's identity during the TLS handshake, establishing a secure Wi-Fi connection and ensuring the transmitted data's confidentiality and integrity.
#include <WiFiClientSecure.h>
const char* ca_cert= \
"-----BEGIN CERTIFICATE-----\n" \
"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" \
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" \
"QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n" \
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" \
"b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n" \
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n" \
"CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n" \
"nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n" \
"43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n" \
"T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n" \
"gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n" \
"BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n" \
"TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n" \
"DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n" \
"hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n" \
"06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n" \
"PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n" \
"YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" \
"CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=" \
"-----END CERTIFICATE-----\n";
// init wifi secure client
WiFiClientSecure espClient;
espClient.setCACert(ca_cert);
The full TLS connection code is available on GitHub.
⚠️ Note: When using TLS on ESP32, memory usage increases significantly. If your application frequently reconnects, consider using a persistent connection strategy to avoid repeated certificate loading overhead.
Publish Messages & Subscribe
Once the connection to the MQTT broker is established successfully, the ESP32 will publish messages to the topic emqx/esp32 and then subscribe to the topic emqx/esp32.
// publish and subscribe
client.publish(topic, "Hi, I'm ESP32 ^^");
client.subscribe(topic);
Receive MQTT Messages
Set the callback function to print the topic name to the serial port and print the message received from the emqx/esp32 topic.
void callback(char *topic, byte *payload, unsigned int length) {
Serial.print("Message arrived in topic: ");
Serial.println(topic);
Serial.print("Message:");
for (int i = 0; i < length; i++) {
Serial.print((char) payload[i]);
}
Serial.println();
Serial.println("-----------------------");
}
Full Code
The full code is as follows:
#include <WiFi.h>
#include <PubSubClient.h>
// WiFi
const char *ssid = "xxxxx"; // Enter your Wi-Fi name
const char *password = "xxxxx"; // Enter Wi-Fi password
// MQTT Broker
const char *mqtt_broker = "broker.emqx.io";
const char *topic = "emqx/esp32";
const char *mqtt_username = "emqx";
const char *mqtt_password = "public";
const int mqtt_port = 1883;
WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
// Set software serial baud to 115200;
Serial.begin(115200);
// Connecting to a WiFi network
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}
Serial.println("Connected to the Wi-Fi network");
//connecting to a mqtt broker
client.setServer(mqtt_broker, mqtt_port);
client.setCallback(callback);
while (!client.connected()) {
String client_id = "esp32-client-";
client_id += String(WiFi.macAddress());
Serial.printf("The client %s connects to the public MQTT broker\n", client_id.c_str());
if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
Serial.println("Public EMQX MQTT broker connected");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(2000);
}
}
// Publish and subscribe
client.publish(topic, "Hi, I'm ESP32 ^^");
client.subscribe(topic);
}
void callback(char *topic, byte *payload, unsigned int length) {
Serial.print("Message arrived in topic: ");
Serial.println(topic);
Serial.print("Message:");
for (int i = 0; i < length; i++) {
Serial.print((char) payload[i]);
}
Serial.println();
Serial.println("-----------------------");
}
void loop() {
client.loop();
}
⚠️ Developer Note on
client.loop(): Theclient.loop()function inside the Arduinovoid loop()block is critical. It processes incoming message queues, handles subscription callbacks, and keeps the MQTT keep-alive ping handshake active. Avoid using blockingdelay()functions inside your loop, as it will cause the ESP32 client to disconnect from the broker.
Running and Testing
- Please follow these steps to upload the complete code using Arduino and power on the ESP32:
- Connect the ESP32 to your computer using a USB cable.
- Open the Arduino IDE and select the appropriate board and port from the "Tools" menu.
- Copy and paste the complete code into the Arduino IDE.
- Click the "Upload" button (or use the shortcut Ctrl+U) to compile and upload the code to the ESP32.
- Wait for the upload process to finish, ensuring there are no errors.
- Once the code is uploaded, disconnect the ESP32 from the computer.
- Power on the ESP32 by connecting it to a suitable power source.
- Open the serial monitor and set the baud rate to 115200. Then, check the connection status of the ESP32 by monitoring the output in the serial monitor.

- Use the MQTTX client to establish a connection with the MQTT broker and publish messages such as
Hi, I'm MQTTXto the ESP32.MQTTX is an elegant cross-platform MQTT 5.0 desktop client that runs on macOS, Linux, and Windows. Its user-friendly chat-style interface enables users to easily create multiple MQTT/MQTTS connections and subscribe/publish MQTT messages.

- You will see the messages published by MQTTX.

Best Practices for MQTT on ESP32
- Always keep
loop()non-blocking - Avoid large dynamic memory allocations inside callback
- Use QoS 0 for telemetry, QoS 1 for commands
- Reconnect both Wi-Fi and MQTT independently
- Keep payload size small (<1KB recommended)
- Use unique client ID (
WiFi.macAddress())
FAQ
Why can't ESP32 connect to MQTT broker?
This is usually caused by:
- Incorrect Wi-Fi credentials
- Broker hostname not reachable from network
- Port mismatch (1883 vs 8883 TLS)
- Firewall blocking MQTT traffic
- Missing
client.loop()in main loop
Debug steps:
- Check Wi-Fi connection first
- Ping broker from network (if possible)
- Try public broker:
broker.emqx.io - Print
client.state()for MQTT error code
Most connection issues are network-related, not code-related.
How do I handle automatic MQTT reconnection on ESP32 if Wi-Fi drops?
Network drops are inevitable in wireless environments. To prevent your ESP32 from remaining permanently offline, you should implement a non-blocking reconnection function inside your loop() that checks both the Wi-Fi and MQTT client states:
void verifyConnections() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi lost. Reconnecting...");
WiFi.disconnect();
WiFi.begin(ssid, password);
return;
}
if (!client.connected()) {
Serial.println("MQTT disconnected. Retrying...");
// Insert your standard non-blocking MQTT connection logic here
}
}
Why does PubSubClient disconnect when sending large payloads, and how do I fix it?
By default, the PubSubClient library enforces a hard limit on message sizes, with a default MQTT_MAX_PACKET_SIZE of 256 bytes (including headers). If your ESP32 attempts to publish or receive a large payload (like a massive JSON string), the broker will abruptly drop the connection.
To fix this, you must increase the buffer size by defining the macro at the very top of your sketch, before importing the library header:
#define MQTT_MAX_PACKET_SIZE 2048 // Increase buffer to 2KB
#include <PubSubClient.h>
In production systems, it is recommended to keep MQTT messages under 1KB whenever possible, even if the buffer is increased, to avoid memory fragmentation and unstable behavior on ESP32.
How can I efficiently publish JSON payloads from ESP32?
The standard industry approach is to pair PubSubClient with the ArduinoJson library. It allows you to serialize sensor readings safely without risking memory fragmentation through raw string concatenation:
#include <ArduinoJson.h>
void publishSensorData() {
JsonDocument doc;
doc["temperature"] = 24.5;
doc["humidity"] = 60.2;
doc["rssi"] = WiFi.RSSI();
char buffer[256];
serializeJson(doc, buffer);
client.publish("emqx/esp32/telemetry", buffer);
}
Why does my ESP32 crash (Guru Meditation Error) inside the MQTT callback?
The execution context of the callback() function is sensitive. If you execute long-running tasks, heavy string manipulations, or perform blocking operations (like delay() or heavy I/O flashing) within the callback, the ESP32 hardware Watchdog Timer (WDT) will trigger a system crash.
Best Practice: Keep your callback restricted to copying the incoming payload data into a global buffer, then set a boolean flag to let your main void loop() handle the actual data processing safely.
Can I subscribe to multiple topics simultaneously using PubSubClient?
Yes. You can invoke client.subscribe() consecutively for different explicit topics right after a connection is established. To route them cleanly, read the incoming topic character array parameters exposed inside your global callback function:
void callback(char* topic, byte* payload, unsigned int length) {
if (strcmp(topic, "emqx/esp32/commands") == 0) {
// Handle incoming control signals
} else if (strcmp(topic, "emqx/esp32/config") == 0) {
// Handle runtime profile configurations
}
}
Why does ESP32 randomly disconnect from MQTT broker?
This is one of the most common issues when using MQTT on ESP32.
Random disconnections are usually caused by:
- Weak or unstable Wi-Fi signal
- Blocking code inside
loop()(e.g. delay, heavy computation) - MQTT keep-alive timeout not being handled
- Power instability when using USB or external sensors
Recommended fix:
Ensure your main loop is non-blocking:
void loop() {
if (!client.connected()) {
reconnectMQTT();
}
client.loop();
}
Avoid long delay() calls. If delays are required, keep them under 100–200ms or replace with millis() timing.
In production systems, Wi-Fi reconnection and MQTT reconnection should always be handled separately.
What is the difference between PubSubClient and ESP-IDF MQTT client?
PubSubClient is a lightweight MQTT library designed for Arduino-based projects, while ESP-IDF provides a native MQTT client for ESP32.
PubSubClient:
- Simple and easy to use
- Good for beginners and prototypes
- Limited memory control
- Max packet size must be manually configured
ESP-IDF MQTT client:
- More stable and production-ready
- Better memory and task management
- Supports advanced features (QoS handling, reconnection logic)
- Recommended for large-scale IoT deployments
If you are building production IoT systems, ESP-IDF is generally preferred.
Why does ESP32 fail to reconnect to MQTT after deep sleep?
After deep sleep, ESP32 behaves like a fresh reboot. This means:
- Wi-Fi must be reinitialized
- MQTT client must reconnect manually
- Subscriptions must be re-subscribed
Common mistake:
Developers assume MQTT connection persists after deep sleep — it does not.
Correct approach:
Re-run full initialization in setup() after wake-up:
- reconnect Wi-Fi
- reconnect MQTT broker
- resubscribe topics
For battery-powered IoT devices, this is critical for reliability.
Summary
In this beginner's guide, we covered the basics of MQTT implementation on the ESP32. We installed the necessary tools, including the ESP32 development board and the PubSubClient library. Readers can establish a secure Wi-Fi connection, connect to an MQTT broker, publish messages, and subscribe to topics through step-by-step instructions. By leveraging MQTT on the ESP32, users can create reliable and efficient IoT applications.
Next, you can check out the MQTT Guide: Beginner to Advanced series provided by EMQ to learn about MQTT protocol features, explore more advanced applications of MQTT, and get started with MQTT application and service development.
Resources
- A Developer's Journey with ESP32 and MQTT Broker
- A Guide on Collecting and Reporting Soil Moisture with ESP32 and Sensor through MQTT
- Using MQTT on ESP8266: A Quick Start Guide
- Remote control LED with ESP8266 and MQTT
- How to Use MQTT on Raspberry Pi with Paho Python Client
- MicroPython MQTT Tutorial Based on Raspberry Pi
- How to Deploy an MQTT Broker on Raspberry Pi