PubSubClient connect() fails with rc=2 when I build the client ID from String objects
Weird one. ESP32, Arduino core 2.0.14, PubSubClient 2.8. This connects fine every time:
mqtt.connect("barn-01", "my_access_token", "");
But I want the client ID to come from the MAC so I can flash the same sketch to five boards, and the token comes from a settings struct. So I did this:
const char* clientId = (String("barn-") + WiFi.macAddress()).c_str();
const char* token = settings.token.c_str();
mqtt.setServer(host.c_str(), 8883);
if (!mqtt.connect(clientId, token, "")) {
Serial.println(mqtt.state());
}
Now it prints 2 forever. Same token, same host. I’m going slightly mad. Is it the colons in the MAC address?
I had something like this, added a delay(500) before connect and it went away.
Can you print what clientId actually contains right before connect?
rc=2 is “client ID rejected”. Colons are allowed in Hermetry client IDs (letters, digits and . _ : -, 1 to 64 chars), so it’s not the MAC format. Something else is getting into the ID.
Printed it, and it’s garbage:
clientId=[□□?□barn-]
sometimes empty, sometimes junk. The delay didn’t change anything.
The String is gone before you use it. (String("barn-") + WiFi.macAddress()) makes a temporary that’s destroyed at the end of that line, so clientId points into freed memory. Whatever the heap does next ends up in your client ID. Bit me on a sensor board years ago and I wasted a day too.
Same trap with setServer(host.c_str(), ...): PubSubClient keeps the pointer, not a copy, so if host is a local String in setup() you’ll get odd reconnect failures later.
Use buffers that live as long as the client:
static char clientId[32];
static char brokerHost[64];
void setupMqtt() {
uint8_t mac[6];
WiFi.macAddress(mac);
snprintf(clientId, sizeof(clientId), "barn-%02x%02x%02x", mac[3], mac[4], mac[5]);
strlcpy(brokerHost, settings.host.c_str(), sizeof(brokerHost));
mqtt.setServer(brokerHost, 8883);
}
// later
mqtt.connect(clientId, settings.token.c_str(), "");
settings.token.c_str() is fine inside the call as long as settings lives globally.
That was it. Static buffers and it connects first time on all five boards. I’d also been building the host in setup() exactly like you said, which explains the random reconnect failures I’d been blaming on my Wi-Fi. Thanks Laura.
- You must be logged in to reply to this topic.
Join the conversation
Sign in to ask and answer, like helpful posts and mark the reply that solved your problem. Every contribution earns points and levels.

