Moving a client off HiveMQ Cloud Serverless changes four things: the hostname, the credentials, the client ID and sometimes the TLS trust settings. Your topics, payloads and application logic stay the same. This article shows exactly what to change for the most common clients, with before-and-after examples using a ConnectMQ private broker as the destination.
The broader process is in the HiveMQ Serverless migration guide.
What Changes and What Stays
| Setting | HiveMQ Cloud Serverless | ConnectMQ |
|---|---|---|
| Hostname | <cluster-id>.s1.eu.hivemq.cloud |
broker.connectmq.com |
| MQTT over TLS | 8883 | 8883 |
| Secure WebSocket | 8884, path /mqtt |
8084, path /mqtt |
| Username and password | Created in the HiveMQ console | Generated per broker in the ConnectMQ portal |
| Client ID | Freely chosen | The issued client ID, optionally with a _suffix |
| Root certificate | Publicly trusted | Let's Encrypt (ISRG Root X1), publicly trusted |
| Topics, payloads, QoS | Unchanged | Unchanged |
Note the secure WebSocket port: browser dashboards often hard-code 8884, while ConnectMQ uses 8084. Check your HiveMQ console for the exact values your cluster used.
ESP32 With Arduino and PubSubClient
Before (HiveMQ Cloud):
const char* MQTT_HOST = "abc123.s1.eu.hivemq.cloud";
const char* MQTT_USER = "hivemq-user";
const char* MQTT_PASS = "hivemq-pass";
String clientId = "sensor-" + WiFi.macAddress();
After (ConnectMQ):
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
const char* MQTT_HOST = "broker.connectmq.com";
const int MQTT_PORT = 8883;
const char* MQTT_USER = "YOUR_USERNAME";
const char* MQTT_PASS = "YOUR_PASSWORD";
const char* CLIENT_ID_BASE = "YOUR_CLIENT_ID";
// ISRG Root X1 (Let's Encrypt), paste the PEM from letsencrypt.org/certificates
static const char ROOT_CA[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
...ISRG Root X1...
-----END CERTIFICATE-----
)EOF";
WiFiClientSecure net;
PubSubClient mqtt(net);
void connectMqtt() {
String mac = WiFi.macAddress();
mac.replace(":", "");
String clientId = String(CLIENT_ID_BASE) + "_" + mac; // issued ID + unique suffix
while (!mqtt.connected()) {
if (mqtt.connect(clientId.c_str(), MQTT_USER, MQTT_PASS)) {
mqtt.publish("site1/esp32/status", "online", true); // republish retained state
mqtt.subscribe("site1/esp32/cmd");
} else {
delay(5000);
}
}
}
void setup() {
// ... connect Wi-Fi first ...
net.setCACert(ROOT_CA);
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqtt.setBufferSize(1024);
connectMqtt();
}
void loop() {
if (!mqtt.connected()) connectMqtt();
mqtt.loop();
}
If your HiveMQ firmware used setInsecure(), take this opportunity to verify certificates properly. More detail is in ESP32 MQTT over SSL. Remember the ESP32 needs the correct time for some TLS stacks; sync NTP before connecting.
Python With paho-mqtt 2.x
Before:
client.username_pw_set("hivemq-user", "hivemq-pass")
client.connect("abc123.s1.eu.hivemq.cloud", 8883)
After:
# pip install "paho-mqtt>=2.0"
import os, ssl
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected:", reason_code)
client.subscribe("site1/#", qos=1)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=os.environ["MQTT_CLIENT_ID"] + "_ingest",
protocol=mqtt.MQTTv5)
client.username_pw_set(os.environ["MQTT_USERNAME"], os.environ["MQTT_PASSWORD"])
client.tls_set(cert_reqs=ssl.CERT_REQUIRED) # system CA store trusts Let's Encrypt
client.on_connect = on_connect
client.on_message = lambda c, u, m: print(m.topic, m.payload.decode())
client.connect("broker.connectmq.com", 8883)
client.loop_forever()
Subscribing in on_connect matters: it restores subscriptions after every reconnect, so the client never depends on session state stored by a broker. See paho-mqtt Python and paho-mqtt reconnect.
Node.js With MQTT.js
// npm install mqtt
const mqtt = require("mqtt");
const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
// was: mqtts://abc123.s1.eu.hivemq.cloud:8883
username: process.env.MQTT_USERNAME,
password: process.env.MQTT_PASSWORD,
clientId: `${process.env.MQTT_CLIENT_ID}_api`,
protocolVersion: 5,
reconnectPeriod: 2000,
});
client.on("connect", () => client.subscribe("site1/+/telemetry", { qos: 1 }));
client.on("message", (topic, payload) => console.log(topic, payload.toString()));
client.on("error", (err) => console.error("MQTT error:", err.message));
For a browser dashboard, use wss://broker.connectmq.com:8084/mqtt with the same options. See MQTT.js with Node.js and MQTT over WebSocket.
Node-RED
In Node-RED, all MQTT nodes share one broker configuration node, so a migration is usually a single edit:
- Open any mqtt in or mqtt out node and click the pencil next to the server.
- Connection tab: set Server to
broker.connectmq.com, Port to8883, tick Use TLS and select a TLS configuration that verifies the server certificate. Set Protocol to MQTT V5 if you use MQTT 5 features. - Client ID: enter your issued client ID with a suffix, for example
YOUR_CLIENT_ID_nodered. - Security tab: enter the new username and password.
- Deploy and check that the nodes show connected.
If the node keeps showing "connecting", see Node-RED MQTT not connecting and Node-RED MQTT TLS.
mosquitto Command-Line Clients
mosquitto_sub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
-u YOUR_USERNAME -P YOUR_PASSWORD -i YOUR_CLIENT_ID_cli \
-t 'site1/#' -v
On Windows or macOS, use --cafile with a PEM bundle that contains ISRG Root X1 instead of --capath.
Troubleshooting Failed Connections
| Symptom | Likely cause | Fix |
|---|---|---|
| Not authorized / bad username or password | Old HiveMQ credentials still in use | Copy the new credentials from the portal |
| Connection refused right after CONNECT | Client ID not matching the issued ID or _suffix pattern |
Use YOUR_CLIENT_ID or YOUR_CLIENT_ID_<suffix> |
| Two devices keep disconnecting each other | Same client ID on both | Derive a unique suffix from MAC or serial number |
| TLS handshake failure | Device trust store lacks ISRG Root X1, or clock is wrong | Add the root certificate, sync time. See MQTT TLS handshake failed |
| Browser cannot connect | Wrong WebSocket port or path | Use wss://broker.connectmq.com:8084/mqtt |
| Connect works, publishes rejected | QoS 2 or payload above plan limit | Use QoS 1 on Serverless (Free), keep payloads under 256 KB, or upgrade |
Reason code 0x97 |
Plan connection quota exceeded | Upgrade the plan before the next wave |
Make the Next Change Easier
While you are editing every client anyway, move the hostname, port, credentials and client ID into configuration that can be updated remotely: a config file, environment variables, a provisioning service or an OTA settings payload. Then rotating credentials or changing brokers in the future is a configuration push, not a firmware project.
You can test any of these examples right now against a free broker at app.connectmq.com.
Frequently Asked Questions
Do I need to change my topics when leaving HiveMQ Cloud?
No. Topics, payloads and QoS levels stay the same. Only the connection settings change.
Why does ConnectMQ require a specific client ID?
Binding client IDs to credentials prevents another tenant or a leaked credential from impersonating your devices. You can still run many clients per credential set by appending a unique suffix.
Is port 8883 the same on both brokers?
Yes, MQTT over TLS uses 8883 on both. The secure WebSocket port differs: ConnectMQ uses 8084 with the path /mqtt.
Can I keep using setInsecure on the ESP32?
It will connect, but it skips server verification and exposes devices to impersonation. Use the ISRG Root X1 certificate instead.



