The safest way to leave HiveMQ Cloud Serverless without interrupting service is to run both brokers in parallel for a while and relay messages between them. Devices and applications can then move one group at a time, and a device that is still on HiveMQ keeps talking to an application that has already moved. This article shows how to build that relay, how to avoid message loops, and how to move clients in waves before the December 31, 2026 deadline.
Why a Relay Is Needed
Neither HiveMQ Cloud Serverless nor a managed cloud broker such as ConnectMQ will bridge to another broker for you on the cloud side. The solution is a small relay process that you run: it connects to both brokers as an ordinary MQTT client, subscribes to selected topics on one side and republishes them on the other. Because it is just a client, it works with any standards-based broker and needs no special permissions.
devices (still on HiveMQ) --> HiveMQ Serverless --relay--> ConnectMQ --> moved consumers
moved command senders --> ConnectMQ --relay--> HiveMQ Serverless --> devices
If you already run Mosquitto on site, its bridge feature can do the same job; see migrate Mosquitto to a cloud MQTT broker and Mosquitto bridge configuration.
The Loop Problem and How to Avoid It
If the relay forwards topic site1/# from HiveMQ to ConnectMQ and also from ConnectMQ to HiveMQ, every message bounces back and forth forever. Prevent loops by design:
- Forward directionally. Telemetry flows one way (old to new), commands the other way (new to old). Do not forward the same topic filter in both directions.
- Use MQTT 5 No Local on subscriptions so the relay does not receive its own publications on the same broker.
- Mark relayed messages with an MQTT 5 user property, such as
relayed=1, and drop messages that already carry it.
The script below applies all three.
A Complete Relay in Python
This relay uses paho-mqtt 2.x and MQTT 5 on both sides. Telemetry and status move from HiveMQ to ConnectMQ; commands move from ConnectMQ to HiveMQ.
# pip install "paho-mqtt>=2.0"
import os, ssl
import paho.mqtt.client as mqtt
from paho.mqtt.packettypes import PacketTypes
from paho.mqtt.properties import Properties
from paho.mqtt.subscribeoptions import SubscribeOptions
# Topic filters per direction (never list the same filter in both)
OLD_TO_NEW = ["site1/+/telemetry", "site1/+/status"]
NEW_TO_OLD = ["site1/+/cmd"]
def make_client(client_id, user, password):
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=client_id, protocol=mqtt.MQTTv5)
c.username_pw_set(user, password)
c.tls_set(cert_reqs=ssl.CERT_REQUIRED)
c.reconnect_delay_set(min_delay=1, max_delay=60)
return c
old = make_client("relay-old-1", os.environ["HIVEMQ_USER"], os.environ["HIVEMQ_PASSWORD"])
new = make_client(os.environ["CMQ_CLIENT_ID"] + "_relay", os.environ["CMQ_USER"], os.environ["CMQ_PASSWORD"])
def is_relayed(msg):
props = getattr(msg, "properties", None)
return any(k == "relayed" for k, _ in (getattr(props, "UserProperty", None) or []))
def forward(target):
def on_message(client, userdata, msg):
if is_relayed(msg):
return
props = Properties(PacketTypes.PUBLISH)
props.UserProperty = [("relayed", "1")]
target.publish(msg.topic, msg.payload, qos=min(msg.qos, 1), retain=msg.retain, properties=props)
return on_message
def subscriber(filters):
def on_connect(client, userdata, flags, reason_code, properties):
print("connected:", reason_code, "subscribing to", filters)
opts = SubscribeOptions(qos=1, noLocal=True)
for f in filters:
client.subscribe(f, options=opts)
return on_connect
old.on_connect, old.on_message = subscriber(OLD_TO_NEW), forward(new)
new.on_connect, new.on_message = subscriber(NEW_TO_OLD), forward(old)
old.connect(os.environ["HIVEMQ_HOST"], 8883)
new.connect("broker.connectmq.com", 8883)
new.loop_start()
old.loop_forever()
Run it on a reliable host close to both brokers, for example a small cloud VM or a container, with the credentials in environment variables. QoS is capped at 1 so the relay works on the free Serverless plan; raise it to 2 on Serverless (Paid) and above if your flows need it. Retained flags are preserved, so retained status messages published on HiveMQ also appear as retained on ConnectMQ.
Two practical notes:
- The relay counts as one connection on each broker. Include it when you size the new plan.
- Monitor it like production. If the relay stops, messages between moved and unmoved clients stop too. Run it under systemd or a container restart policy.
The Wave Plan
Move clients in an order that keeps every data flow working.
| Wave | Who moves | Why in this order |
|---|---|---|
| 0 | The relay starts | Both brokers see the same telemetry and commands |
| 1 | Backend consumers: databases, rule engines, Node-RED, dashboards | They receive device data through the relay |
| 2 | A pilot group of devices from different sites and firmware versions | Real-world validation with limited risk |
| 3 to N | Remaining devices in batches by site or product line | Controlled rollout with checkpoints |
| Final | Command producers, then stop the relay | Devices are already on the new broker |
After each wave, check:
- The connection count in the ConnectMQ dashboard matches the number of moved clients.
- Expected topics appear in the live topic explorer.
- Connection state per client on
$SYS/broker/connection/{clientId}/stateshows the moved devices online. - No moved client is still connecting to HiveMQ (check the HiveMQ console).
- The connection count stays within plan limits; MQTT 5 clients receive
0x97if a quota is exceeded.
Rollback
While the old cluster still works, every wave can be rolled back by restoring the previous connection settings. Keep the old settings available in your provisioning system until the final wave is complete. This is the main reason not to leave the migration until the last days of December: after December 31, 2026 there is nothing to roll back to.
Cutover Checklist
- All devices and applications run on the new broker.
- The HiveMQ console shows no client connections except the relay.
- Retained state is present on the new broker, republished by devices or restored from an export. See HiveMQ Serverless data deletion.
- Stop the relay and watch for a day for any client that reappears on HiveMQ.
- Delete the HiveMQ Serverless cluster and remove the old hostname from configuration, firmware defaults and documentation.
For the end-to-end process, see the HiveMQ Serverless migration guide. You can build and test the relay today against a free broker at app.connectmq.com.
Frequently Asked Questions
Can HiveMQ Cloud bridge directly to ConnectMQ?
Not on the cloud side. Run a relay client such as the script above, or a Mosquitto bridge on your own infrastructure, which connects to both brokers as a normal MQTT client.
Will devices notice the migration?
Devices that move see a short reconnect when their settings change. Devices that have not moved yet see no change at all, because the relay keeps their data flowing to moved applications.
Does the relay add latency?
It adds one extra hop, typically a few milliseconds to tens of milliseconds depending on where it runs. Place it close to both brokers and remove it once the migration is complete.
Should the relay use QoS 1 or QoS 2?
QoS 1 is a good default and works on every ConnectMQ plan. Make sure consumers handle the occasional duplicate, which QoS 1 allows. Use QoS 2 only where duplicates are unacceptable and your plan supports it.



