This ESP32-C6 MQTT tutorial gets a C6 board publishing telemetry and receiving commands in about fifteen minutes. You will install the right Arduino core, publish the chip's internal temperature to broker.connectmq.com, switch the onboard RGB LED from your laptop, and learn which habits from the classic ESP32 no longer apply.
What Makes the ESP32-C6 Different
The ESP32-C6 is not just a newer ESP32. It uses a different CPU architecture and a different radio set, and a few of those changes show up immediately in Arduino sketches.
| Feature | Classic ESP32 | ESP32-C6 |
|---|---|---|
| CPU | Dual-core Xtensa LX6, up to 240 MHz | Single-core RISC-V, up to 160 MHz, plus a low-power RISC-V core |
| Wi-Fi | 802.11 b/g/n, 2.4 GHz | 802.11ax (Wi-Fi 6), 2.4 GHz only |
| Bluetooth | Classic and BLE 4.2 | BLE 5 only, no Classic |
| 802.15.4 | No | Yes (Thread, Zigbee) |
| Arduino core | 2.x and 3.x | 3.x only |
| USB | External USB-UART chip | Native USB Serial/JTAG plus UART on most DevKits |
| Onboard LED (DevKitC-1) | Usually a plain LED on GPIO 2 | Addressable RGB LED on GPIO 8 |
For MQTT, the practical consequences are:
- You need Arduino core 3.x. The C6 is not available in the 2.x board packages.
- There is only one application core. Any code that pins tasks to core 1 must change to core 0.
- Serial may appear on a different port. If nothing prints, enable "USB CDC On Boot" or plug into the UART port.
- Wi-Fi 6 is optional, not required. The C6 connects to ordinary 802.11n access points too. It still cannot see 5 GHz networks.
The MQTT protocol itself does not care about any of this. The same PubSubClient code that runs on an ESP32 runs on a C6, which is why this tutorial focuses on the setup details that trip people up.
Prerequisites
- An ESP32-C6 board. The steps assume the Espressif ESP32-C6-DevKitC-1; other C6 boards work with small pin changes.
- Arduino IDE 2.x.
- The esp32 board package by Espressif Systems, version 3.0 or newer, from the Boards Manager.
- The PubSubClient library by Nick O'Leary from the Library Manager.
- Mosquitto command-line clients on your computer.
Setting Up Arduino for the ESP32-C6
- Open Boards Manager, search for
esp32, and install or update the Espressif package to a 3.x release. - Select Tools > Board > esp32 > ESP32C6 Dev Module.
- On the DevKitC-1, connect the USB-C port labelled UART for the simplest experience. If you use the port labelled USB, set Tools > USB CDC On Boot > Enabled so
Serialmaps to native USB. - Pick the matching COM port and upload a blank sketch once to confirm the toolchain works.
If the upload fails with a connection timeout, hold BOOT, tap RESET, release BOOT, and try again. This forces the ROM bootloader.
The ESP32-C6 MQTT Sketch
The sketch publishes the internal temperature sensor reading, Wi-Fi signal strength and free heap every ten seconds, subscribes to an LED command topic, and reports the LED state as a retained message.
#include <WiFi.h>
#include <PubSubClient.h>
const char* WIFI_SSID = "YOUR_WIFI_SSID";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* PREFIX = "connectmq/demo/c6x41z"; // change to your own random id
WiFiClient net;
PubSubClient mqtt(net);
String clientId;
String topicTelemetry, topicLedSet, topicLedState, topicStatus;
unsigned long lastPublish = 0;
uint8_t ledR = 0, ledG = 0, ledB = 0;
void setLed(uint8_t r, uint8_t g, uint8_t b) {
ledR = r; ledG = g; ledB = b;
rgbLedWrite(RGB_BUILTIN, r, g, b); // Arduino core 3.x API
char state[40];
snprintf(state, sizeof(state), "{\"r\":%u,\"g\":%u,\"b\":%u}", r, g, b);
mqtt.publish(topicLedState.c_str(), state, true);
}
void onMessage(char* topic, byte* payload, unsigned int length) {
String msg;
for (unsigned int i = 0; i < length; i++) msg += (char)payload[i];
msg.trim();
msg.toUpperCase();
Serial.printf("Command on %s: %s\n", topic, msg.c_str());
if (msg == "OFF") setLed(0, 0, 0);
else if (msg == "RED") setLed(40, 0, 0);
else if (msg == "GREEN") setLed(0, 40, 0);
else if (msg == "BLUE") setLed(0, 0, 40);
else if (msg == "WHITE") setLed(30, 30, 30);
}
void connectWifi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to Wi-Fi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.printf("\nIP %s, RSSI %d dBm\n", WiFi.localIP().toString().c_str(), WiFi.RSSI());
}
void connectMqtt() {
while (!mqtt.connected()) {
Serial.print("Connecting to MQTT... ");
if (mqtt.connect(clientId.c_str(), topicStatus.c_str(), 1, true, "offline")) {
Serial.println("connected");
mqtt.publish(topicStatus.c_str(), "online", true);
mqtt.subscribe(topicLedSet.c_str(), 1);
} else {
Serial.printf("failed, state %d, retrying in 5 s\n", mqtt.state());
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
delay(500);
clientId = "esp32c6-" + String((uint32_t)ESP.getEfuseMac(), HEX);
topicTelemetry = String(PREFIX) + "/telemetry";
topicLedSet = String(PREFIX) + "/led/set";
topicLedState = String(PREFIX) + "/led/state";
topicStatus = String(PREFIX) + "/status";
connectWifi();
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqtt.setCallback(onMessage);
mqtt.setBufferSize(512);
connectMqtt();
setLed(0, 0, 0);
}
void loop() {
if (WiFi.status() != WL_CONNECTED) connectWifi();
if (!mqtt.connected()) connectMqtt();
mqtt.loop();
if (millis() - lastPublish >= 10000) {
lastPublish = millis();
char payload[160];
snprintf(payload, sizeof(payload),
"{\"chipTemp\":%.1f,\"rssi\":%d,\"freeHeap\":%lu,\"uptime\":%lu}",
temperatureRead(), WiFi.RSSI(),
(unsigned long)ESP.getFreeHeap(), millis() / 1000);
mqtt.publish(topicTelemetry.c_str(), payload);
Serial.println(payload);
}
}
The internal temperature sensor measures the die, not the room, so expect values several degrees above ambient. It is useful as a health signal and as a zero-wiring demo value.
Testing ESP32-C6 MQTT Messages
Open a terminal and subscribe to everything under your prefix:
mosquitto_sub -h broker.connectmq.com -p 1883 -i c6-viewer-x41z -t "connectmq/demo/c6x41z/#" -v
You should see status online, the retained LED state and a telemetry message every ten seconds. In a second terminal, send a command:
mosquitto_pub -h broker.connectmq.com -p 1883 -i c6-cmd-x41z -t "connectmq/demo/c6x41z/led/set" -m "green" -q 1
The RGB LED turns green and a new retained state appears. Because the state is retained, any client that subscribes later immediately learns the current colour. The ConnectMQ public area needs no account but is visible to everyone, so stick to demo data; the public MQTT test broker page explains its limits, including 10 messages per second per client.
Porting Classic ESP32 Code to the C6
Most sketches compile unchanged. These are the edits you are most likely to need:
- Task pinning. Replace
xTaskCreatePinnedToCore(..., 1)with core 0, or callxTaskCreate. The ESP32 FreeRTOS MQTT guide shows a task layout that works on both chip families with this one change. - LED pins.
digitalWrite(2, HIGH)lights nothing on a DevKitC-1. UsergbLedWrite(RGB_BUILTIN, r, g, b). - ADC pins. The C6 has a single ADC on GPIO 0 to 6. Pin numbers like 34 or 36 from classic ESP32 examples do not exist.
- Deprecated APIs. Core 3.x renamed or removed several functions, for example
neopixelWritebecamergbLedWriteand the LEDC PWM API changed toledcAttach. Check compiler errors against the migration notes in the Arduino-ESP32 documentation. - Bluetooth Classic.
BluetoothSerialis not supported. Use BLE instead.
If you build with PlatformIO, set the platform to a release that ships Arduino core 3.x for the C6; the PlatformIO MQTT setup walks through a reproducible project file.
Troubleshooting
mqtt.state()returns -2. The TCP connection failed. Check that the board actually has an IP address and that your network allows outbound port 1883. Some guest networks block it; try port 8883 with TLS instead.mqtt.state()returns 2. The broker rejected the client ID. On the public area it must be non-empty and unique, which the eFuse MAC suffix ensures.- Connects, then drops every few seconds. Two devices are using the same client ID, and each new connection kicks the other off. This often happens when you flash the same hard-coded ID to two boards.
- Wi-Fi never connects to a Wi-Fi 6 router. Make sure the 2.4 GHz band is enabled and not hidden behind a band-steering setting that pushes clients to 5 GHz only. WPA3-only networks can also cause trouble; try WPA2/WPA3 mixed mode.
- No serial output. Toggle USB CDC On Boot or switch to the UART port.
Going to Production on a Cloud Broker
For real devices, switch to TLS on port 8883 with credentials. Create a broker at app.connectmq.com and copy the username, password and client ID it generates. Change WiFiClient to WiFiClientSecure, load the ISRG Root X1 certificate with net.setCACert(...), set the port to 8883, and pass the credentials to mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD", ...). The C6 handles the TLS handshake comfortably, though it takes a little longer than on a 240 MHz classic ESP32.
From there, the portal's live topic explorer shows your C6 messages as they arrive, and the devices view groups boards by site and line if you use ISA-95 style topic names. If you are new to brokers in general, what an MQTT broker does is a short primer, and the ESP32 IoT tutorial lists every project in this series.
Run Your ESP32-C6 Fleet on ConnectMQ
The ESP32-C6 is a strong choice for new designs: Wi-Fi 6 efficiency, BLE 5 and a modern toolchain. Pair it with a cloud MQTT broker you do not have to operate. ConnectMQ gives you TLS on 8883, MQTT 3.1.1 and 5.0, and a free Serverless plan with no credit card, so you can move from the public demo area to authenticated devices in minutes. If you want MQTT 5 properties on the C6, ESP-IDF is the way to go; see esp-mqtt with MQTT 5.
Frequently Asked Questions
Does the ESP32-C6 support MQTT over Wi-Fi 6?
Yes. MQTT runs over TCP, so it works on any Wi-Fi standard the C6 supports, including 802.11ax on 2.4 GHz. Wi-Fi 6 mainly helps with power efficiency and crowded networks.
Can I use Thread or Zigbee on the C6 to reach an MQTT broker?
The C6 radio supports 802.15.4, but MQTT needs an IP path to the broker. A Thread network needs a border router, and Zigbee devices usually need a gateway that translates to MQTT.
Why does my old ESP32 sketch not compile for the C6?
The C6 requires Arduino core 3.x, which changed several APIs, and it lacks Bluetooth Classic and the second core. Update renamed functions and remove core 1 pinning.
Is the internal temperature sensor accurate enough for room temperature?
No. It measures the chip die and runs warmer than the room. Use an external sensor such as a DHT22 or BME280 for ambient readings.



