A good mosquitto bridge configuration lets a local broker on a Raspberry Pi keep serving devices on the LAN while forwarding exactly the topics you choose to a cloud broker. In this tutorial you will build a bridge that connects to ConnectMQ over TLS with portal credentials, remaps topics so each site has its own namespace, sends commands back down, queues messages through internet outages and avoids the classic message loop. Each option is explained, so you can adapt the file instead of copying it blindly.
How a Mosquitto Bridge Works
A bridge is not a special protocol. The local Mosquitto broker opens an outbound connection to the remote broker and behaves like a normal MQTT client: it subscribes on one side and republishes on the other, according to topic lines in its config. That has three useful consequences:
- No inbound ports. The Pi connects out over port 8883, just like a browser connecting to a website. Your router stays closed.
- The remote broker needs nothing special. Any standards-compliant broker accepts a bridge, because it simply sees a client log in with a username, password and client ID.
- You choose what crosses the boundary. Only topics matched by a
topicline leave or enter the site.
In this setup the remote side is ConnectMQ, a managed MQTT broker. The bridge authenticates with the generated credentials from the portal like any other device. If you have not set up the local broker yet, follow install Mosquitto on Raspberry Pi first.
Sensors / PLC gateway / Node-RED (LAN)
| mqtt://pi:1883 (local users)
v
+---------------------------+
| Mosquitto on Raspberry Pi |
| bridge "connectmq" |
+---------------------------+
| mqtts://broker.connectmq.com:8883
| remote_username / remote_password / remote_clientid
v
+---------------------------+
| ConnectMQ cloud broker | dashboards, phones, other sites
+---------------------------+
Before You Start
- A Raspberry Pi with Mosquitto 2.0 running and at least one authenticated local listener.
- A cloud broker with credentials. Sign up at the portal, choose a plan, create a broker and copy the generated username, password and client ID. The client ID is bound to those credentials, so the bridge must use it exactly.
- A plan for topic names. Decide how local topics should look in the cloud. A site prefix such as
site1/keeps several Pis from colliding.
For a quick experiment without an account you can bridge to the public MQTT test broker on port 1883 with no credentials and any unique client ID, using a random prefix like connectmq/demo/3c7d52/. Everything there is publicly readable, so use only dummy data.
The Complete Mosquitto Bridge Configuration
Create /etc/mosquitto/conf.d/bridge-connectmq.conf:
# ---- Connection ----
connection connectmq
address broker.connectmq.com:8883
bridge_protocol_version mqttv311
try_private false
start_type automatic
restart_timeout 5 60
keepalive_interval 60
# ---- TLS ----
bridge_capath /etc/ssl/certs
bridge_insecure false
# ---- Credentials from the ConnectMQ portal ----
remote_clientid YOUR_CLIENT_ID
remote_username YOUR_USERNAME
remote_password YOUR_PASSWORD
# ---- Session and queueing ----
cleansession false
local_clientid bridge-connectmq-local
# ---- Status topic (published on the remote side) ----
notifications true
notifications_local_only false
notification_topic site1/bridge/state
# ---- Topic mapping ----
# Telemetry up: local "sensors/#" -> remote "site1/sensors/#"
topic sensors/# out 1 "" site1/
# Machine states up, retained values preserved
topic machines/+/state out 1 "" site1/
# Commands down: remote "site1/cmd/#" -> local "cmd/#"
topic cmd/# in 1 "" site1/
Restart and follow the log:
sudo chmod 0640 /etc/mosquitto/conf.d/bridge-connectmq.conf
sudo chown root:mosquitto /etc/mosquitto/conf.d/bridge-connectmq.conf
sudo systemctl restart mosquitto
sudo journalctl -u mosquitto -f
You should see Connecting bridge connectmq (broker.connectmq.com:8883) followed by no errors. The permission change matters because the file contains the remote password.
Option by Option
| Option | Value here | Why |
|---|---|---|
address |
broker.connectmq.com:8883 |
TLS port of the cloud broker |
bridge_protocol_version |
mqttv311 |
Widely supported; MQTT 5 bridging is also possible on recent Mosquitto |
try_private |
false |
Avoids a Mosquitto-only bridge flag that non-Mosquitto brokers may reject |
restart_timeout |
5 60 |
Back off from 5 s up to 60 s between reconnect attempts |
bridge_capath |
/etc/ssl/certs |
System CA store validates the broker's Let's Encrypt certificate |
bridge_insecure |
false |
Keep hostname verification on, always |
remote_clientid |
Portal client ID | Must match the issued credentials |
cleansession |
false |
Keep sessions so QoS 1 messages queue during outages |
notifications |
true |
Publishes 1 when the bridge connects and 0 (as last will) when it drops |
notification_topic |
site1/bridge/state |
Keeps the status inside your own namespace |
Understanding the topic Line
The syntax is topic <pattern> <direction> <qos> <local-prefix> <remote-prefix>. Mosquitto strips the local prefix from a local topic and adds the remote prefix when forwarding out, and does the reverse for in. With an empty local prefix (written as "") and remote prefix site1/:
- Local
sensors/boiler/tempbecomes remotesite1/sensors/boiler/temp. - Remote
site1/cmd/pump1/setbecomes localcmd/pump1/set.
Note that the remote prefix ends with a slash. Without it you get site1sensors/..., a mistake that is easy to make and hard to spot.
QoS on the Bridge
The QoS on a topic line is the maximum used across the bridge. QoS 1 is the practical choice: it guarantees delivery with acknowledgements and is supported on every plan, including the free Serverless plan, which caps QoS at 1. Use QoS 2 only if you are on a plan that supports it and the data truly cannot tolerate duplicates. The MQTT QoS levels explained article covers the trade-offs.
Queueing During Internet Outages
With cleansession false, the local broker keeps the bridge's session while the connection is down and queues QoS 1 messages for it. When the link returns, the backlog drains to the cloud. The queue is bounded by max_queued_messages (and optionally max_queued_bytes) in your main config. Size it for the longest outage you want to cover; on a Pi with an SD card, keep it moderate, because persisted queues are written to disk at each autosave. QoS 0 messages are not queued, which is another reason to bridge telemetry at QoS 1.
Remember that the cloud side applies its own limits too. If a long backlog arrives in a burst, a broker with per-plan quotas and flood protection may throttle it, so very long outages are better handled by an application-level buffer such as the one in the offline message buffering guide.
Testing the Bridge End to End
Subscribe on the cloud side. With the public broker you can use mosquitto_sub directly; with a private broker use a second set of credentials or the portal's in-browser MQTT client:
mosquitto_sub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
-u YOUR_USERNAME_2 -P YOUR_PASSWORD_2 -i YOUR_CLIENT_ID_2 \
-t 'site1/#' -v
Publish locally on the Pi:
mosquitto_pub -h localhost -u sensors -P 'sensors-password' -i t1 -q 1 \
-t sensors/boiler/temp -m 64.2
The cloud subscriber prints site1/sensors/boiler/temp 64.2 and site1/bridge/state 1. Now test the downlink. Subscribe locally to cmd/#, then publish from the cloud side to site1/cmd/pump1/set. The message arrives locally as cmd/pump1/set.
Finally, test an outage: stop the network on the Pi (sudo nmcli networking off), publish a few QoS 1 messages locally, re-enable networking and watch them arrive in the cloud. The bridge state topic goes to 0 while the link is down, delivered by the broker as the bridge's last will.
Avoiding Loops in Your Mosquitto Bridge Configuration
A loop happens when a message forwarded out comes back in and is forwarded out again. The most common cause is a both rule, or overlapping in and out patterns, on the same topics:
# Dangerous: anything under site1/ bounces back and forth
topic # both 1 "" site1/
Keep directions on separate subtrees: telemetry and states go out, commands come in under a different branch (cmd/). If you truly need both, prefer MQTT 5 bridging with no-local subscriptions where your Mosquitto version supports it, and test carefully. Never bridge # without a prefix in either direction.
Multiple Sites, One Cloud Broker
Each Pi gets its own credentials and its own prefix (site1/, site2/, ...). Dashboards subscribe to +/sensors/# to see every site, or to one prefix for a single site. Because each bridge has a unique client ID tied to its credentials, revoking one site never affects the others. Paid Serverless plans add shared subscriptions, which help when several cloud consumers need to split the combined stream. Industrial sites can go further and adopt an ISA-95 style hierarchy such as enterprise/site/area/line/cell, which the portal detects and shows in its devices view.
Troubleshooting
| Log message or symptom | Cause | Fix |
|---|---|---|
Connection Refused: not authorised |
Wrong credentials or client ID | Copy all three from the portal again |
certificate verify failed |
Missing CA store or wrong time | Install ca-certificates, check NTP with timedatectl |
| Bridge connects, nothing arrives | Topic pattern or prefix mismatch | Remember the trailing slash in prefixes |
| Connection drops every few seconds | Another client using the same client ID | One client ID per connection |
| Messages lost during outages | QoS 0 or cleansession true |
Use QoS 1 and cleansession false |
| Message storm after enabling the bridge | Loop from overlapping in/out rules | Separate subtrees for each direction |
Bridge Your Pi to ConnectMQ
Create a free Serverless broker at app.connectmq.com, no credit card required, paste the generated username, password and client ID into your bridge file and watch your site's topics appear in the portal's live topic explorer. For the broader gateway design around this bridge, read Raspberry Pi as an IoT gateway, and for the full Pi series, the Raspberry Pi MQTT tutorial.
Frequently Asked Questions
Does ConnectMQ need a special bridge feature for Mosquitto?
No. The Mosquitto bridge connects as a normal MQTT client using the username, password and client ID from the portal, so any plan works.
Should I bridge with MQTT 3.1.1 or MQTT 5?
MQTT 3.1.1 is the simplest and most widely tested choice for bridges. Recent Mosquitto versions support mqttv50 bridging if you need MQTT 5 features on the bridge link.
Why set try_private to false?
When enabled, Mosquitto signals that it is a bridge using a non-standard protocol flag intended for Mosquitto-to-Mosquitto links. Turning it off keeps the connection fully standard for other brokers.
How many messages does the bridge queue during an outage?
As many as max_queued_messages and max_queued_bytes allow, for QoS 1 and 2 messages with cleansession false. QoS 0 messages are dropped while the link is down.



