Messages from somebody else's broker, and Home Assistant on yours
Part 5 was about getting data out of EMQX — a rule fires, an action runs, a connector carries the result somewhere else. This part goes the other way. A Source is the entry point that brings messages from an external MQTT broker back into your own EMQX, and a Republish action puts them onto a local topic your own clients can actually read. Then comes the reason most people wanted this in the first place: pointing Home Assistant's MQTT integration at EMQX, letting discovery bring the devices in by itself, and moving Zigbee2MQTT and an old Mosquitto setup across without losing an evening to it.
topic through to message_received_atNot every device is going to connect to your broker
You may have a Zigbee gateway, or a cloud platform, that already publishes its data to some other MQTT broker. It is not going to move house just because you installed EMQX. To get those external messages into your EMQX — and from there into a rule, or into Home Assistant — you need a way in. That way in is called a Source.
The Sink from Part 5 sends data out. A Source is the opposite: it collects data from a remote broker and hands it to a rule. This is data import, and it is the missing half of the picture.
A Sink is the outbox on your desk: you put something in it and it leaves the building. A Source is the letter slot in the front door. Post comes through the slot and lands in the hall. It has arrived, and it is inside — but it is still lying on the mat. Somebody still has to pick it up and carry it to the right room. In EMQX, that somebody is the Republish action, and if you forget to hire them the post just piles up in the hall.
Connecting two MQTT brokers this way is what most people call an MQTT broker bridge. The EMQX 5.x documentation calls it MQTT Broker Data Integration, which is the term you will hit in the official docs. Whichever name you use, the mechanism is the same: EMQX connects to another MQTT service as a client, and exchanges messages in both directions.
| Term | Plain English | In one line |
|---|---|---|
| Source | input source | Where external data enters EMQX (ingress) |
| Sink | output target | Where EMQX data goes out to an external system (egress) |
| MQTT Broker Bridge | MQTT bridge | Moves messages between two MQTT brokers |
| Ingress | inbound | Brings messages from a remote broker into EMQX |
| Egress | outbound | Publishes EMQX messages to a remote broker |
The two directions are not separate features. Both share the same Connector you met in Part 5, and one connection can carry several bridge rules, each with its own topic mapping and its own transformation.
flowchart LR
subgraph EG["Egress — a Sink"]
direction LR
L1["Local topic t/1"] --> S1["MQTT Sink"] --> R1["Remote pub/t/1"]
end
subgraph IN["Ingress — a Source"]
direction LR
R2["Remote f/1"] --> S2["MQTT Source"] --> P["Republish action"] --> L2["Local sub/f/1"]
end
Five steps, following the official tutorial
The worked example below is the one in the official tutorial: bridge whatever a remote broker receives on f/# onto your local sub/#. The remote broker is the public test broker broker.emqx.io, so you can run this without owning a second broker of your own. The menu paths are written against the EMQX 5.8.9 (Open Source) Dashboard, which is the version this guide follows throughout.
-
Step 1
Create the MQTT Broker Connector
In the Dashboard go to Integration → Connectors → Create and pick MQTT Broker. Name it
my_mqtt_bridgeand set the server to:broker.emqx.io:1883If the remote broker requires authentication, fill in the credentials here. Then click Create.
-
Step 2
Create the rule and add the MQTT Source
Go to Integration → Rules → Create. On the Data Inputs tab, delete the default Message input, click Add Input, pick MQTT Broker, and choose the Connector you just made. Then set the subscribe Topic and the QoS. The tutorial uses:
$share/1/f/#That leading
$share/1/is a shared subscription, and the next section explains why it is there rather than a plainf/#. -
Step 3
Check the rule SQL
Once the Source is added, the rule SQL rewrites itself and becomes this on its own:
SELECT * FROM "$bridges/mqtt:my_source"Read it as a sentence: the data source for this rule is that MQTT broker bridge, not a local topic. You did not type it; adding the Source produced it.
-
Step 4
Add the Republish action
Switch to the Action Outputs tab, click + Add Action and pick Republish. Three fields:
Topic—sub/${topic}QoS—${qos}Payload—${payload}The
${topic}in there is the topic of the original remote message. So a remotef/1becomes a localsub/f/1: the prefix is yours, the tail is theirs. -
Step 5
Create it and verify
Click Create to finish the rule. Then test it end to end: subscribe to
sub/#locally, publish a message tof/1on the remote broker, and it should arrive locally onsub/f/1. If it does not, the first row of the troubleshooting table further down is exactly this case.
flowchart TD A["A message lands on f/1
at the remote broker"] --> B["MQTT Source subscribes
$share/1/f/#"] B --> C["Rule reads
$bridges/mqtt:my_source"] C --> D["Republish action writes
sub/${topic}"] D --> E["Local subscriber on sub/#
receives sub/f/1"]
Wildcards, shared subscriptions, and the seven fields
Two things are worth watching when you create an MQTT Source.
The first is the subscribe topic. It accepts the + and # wildcards, so one Source can pick up a whole family of remote topics rather than one at a time. The usual rules apply: + matches exactly one level, and # matches the rest and is only allowed at the end.
The second is the shared subscription. When EMQX runs as a cluster, or when the Connector has a connection pool open, several clients end up subscribed to the same topic at once — and each of them receives the message. That is not a bug, it is what a plain subscription means. The official advice is to spread that load with a shared subscription:
$share/<group>/topic — the general form$share/1/f/# — the form used in the tutorial aboveFour housemates each take out their own subscription to the same newspaper. Every morning four identical papers land on the mat, and everyone reads the same headlines four times over. A shared subscription is the house agreeing to one delivery, with whoever gets up first bringing it in. Same paper, same news, one copy.
What the Source then hands to your rule SQL is a fixed set of seven fields:
| Field | What it means |
|---|---|
topic | The topic of the original message |
server | The address of the source broker |
payload | The message payload |
qos | The QoS of the message |
retain | Whether the message is retained |
pub_props | MQTT 5.0 message properties (user property and so on) |
message_received_at | The time it was received, in milliseconds |
A rule that wants those fields uses $bridges/mqtt:<name> as its data source, where <name> is the name of the Connector or Source. Get that name wrong and the rule still exists, still runs, and quietly gives you empty fields.
The egress side, for completeness
Going the other way is simpler, because no Republish is involved. You create an MQTT Sink (egress) that publishes a local topic to the remote broker. A rule of SELECT * FROM "t/#" pointed at the target pub/${topic} forwards your local t/1 to pub/t/1 on the remote broker. On the way out, QoS and retain can carry over from the original message through the ${qos} and ${flags.retain} placeholders.
To declare all of this in a config file instead of clicking through the Dashboard, create the matching ingress (Source) and egress (Sink) bridges in the rule_engine and connector/bridges sections, mirroring the rule's SQL.
Point Home Assistant at EMQX
Home Assistant's built-in MQTT integration needs the smallest of setups — a broker address plus credentials — which is why so many installations end up on Mosquitto and stay there. Your host does not have to. The main reason to switch to the Woow EMQX add-on (EMQX 5.8.9) is that it takes over the whole MQTT lifecycle: Dashboard, ACL, rules, monitoring. The one condition is that Home Assistant can actually reach your EMQX.
Two facts shape the setup, and both are about the add-on rather than about Home Assistant.
The Woow EMQX add-on uses host_network, which means it opens port 1883 (MQTT) directly on the host. So in the Home Assistant setup you can simply put homeassistant in Broker — or localhost — without hunting for a container address.
And the connection needs a user account in EMQX. Woow EMQX requires Authentication to be set up first, so nothing can connect without credentials. That fixes the order of operations: create the user in EMQX first, then create the integration in Home Assistant.
-
Step 1
Create an MQTT user in EMQX
Start in the EMQX Dashboard: Access Control → Authentication, pick Password-Based → Built-in Database, and create a username and password. This is the account Home Assistant will connect with, so write it down where you can find it again in two minutes.
-
Step 2
Open the MQTT integration in Home Assistant
In the Home Assistant panel: Settings → Devices & services → Add integration, then search for MQTT. If it is not installed yet, Home Assistant offers to add it for you.
-
Step 3
Fill in the broker connection details
Four fields, and they are the whole configuration:
Broker—homeassistant(orlocalhost)Port—1883Username— the account you created in step 1Password— its password -
Step 4
Save and confirm
After you save, Home Assistant should report that the connection succeeded. Now go back to the Clients page of the EMQX Dashboard: this MQTT client from Home Assistant will be sitting there, online. That is the confirmation worth trusting — it is the broker's own view, not a message from the side that just tried.
-
Step 5
Check discovery
If a set of discovery messages is already on the
homeassistant/topic, Home Assistant should find those devices by itself. If not, you can still add one by hand with Add device.
flowchart TD A["EMQX: Access Control → Authentication
Password-Based → Built-in Database"] --> B["A username and password
now exist in EMQX"] B --> C["HA: Settings → Devices & services
→ Add integration → MQTT"] C --> D["Broker homeassistant, Port 1883,
Username and Password from the top"] D --> E["HA reports the connection succeeded"] E --> F["The HA client appears on
the EMQX Clients page"]
Devices introduce themselves, and so does Home Assistant
Discovery is what makes the Home Assistant MQTT integration convenient. The integration subscribes to the discovery prefix — the homeassistant/ topic by default — and when a device publishes a discovery message in the expected format, Home Assistant creates the matching entity for you. Nothing to add by hand, no YAML.
The integration also announces itself, using two MQTT features that are easy to confuse:
homeassistant/status, for example — which is how everyone else, and your EMQX rules, can tell whether Home Assistant is online or offline.The birth message is you calling out “I'm back” as you come through the door. The will is the note you left with the doorman on your way out: if I don't come back, tell them I've gone. You cannot announce your own disappearance — that is the whole point of it. Somebody else has to do it, and the broker is the one holding the note.
In practice, showing whether Home Assistant is online usually relies on this status topic. To put an EMQX rule on the Home Assistant offline notice, point the rule's FROM clause at that event source.
flowchart TD A["The HA MQTT integration connects"] --> B["Publishes a birth message
on homeassistant/status"] A --> C["Subscribes to the discovery prefix
homeassistant/"] A --> D["Registers a will
with the broker"] C --> E["A device publishes a discovery message
in the expected format"] E --> F["HA creates the matching entity
on its own"] D --> G["Connection lost unexpectedly:
the broker publishes offline
on HA's behalf"]
| Term | Plain English | In one line |
|---|---|---|
| MQTT Integration | HA's broker connection | The integration HA uses to connect to an MQTT broker (EMQX) |
| Discovery | automatic device setup | HA adds the MQTT devices that announce themselves, without your help |
| Birth Message | online announcement | The “I'm here” message the integration publishes when it comes online |
| Status Topic | online/offline topic | The topic that says whether the integration is online or offline |
| Will | offline notice | The notice the broker sends on the client's behalf when it drops offline unexpectedly |
| State Topic | device state topic | The topic a device publishes its state updates on |
homeassistant/, and you can name the birth and will topics yourself.One port, two brokers, and only one winner
Zigbee2MQTT (Z2M) is the common integration for bridging Zigbee devices onto MQTT, and it is usually the second thing you point at the new broker. Because the Woow EMQX add-on runs with host_network, the broker address Z2M connects to is usually homeassistant or this add-on's slug — a0d7b954-emqx, for example — on port 1883, with the account you created in EMQX.
Migrating away from Mosquitto starts with one hard constraint: Mosquitto and EMQX cannot run at the same time. Both take port 1883.
Two shops cannot both be number 1883 on the same street. It is not a matter of being polite about it or taking turns — the post simply has one address to go to, and whoever is registered there gets it. You either move one shop to a different number, or you close one down.
The migration outline is four steps, and the order matters:
-
Step 1
Disable your existing Mosquitto add-on
This frees up 1883. Until it is done, nothing else in this list can succeed.
-
Step 2
Point your existing devices and integrations at EMQX
The broker of everything currently talking to Mosquitto now becomes
homeassistant, port1883, with the EMQX account. -
Step 3
Create the same MQTT users in EMQX
And carry the retained message and ACL settings over to the EMQX side as well. This is the part that takes real time on a mature installation.
-
Step 4
Start EMQX and confirm
Check that Home Assistant, Z2M and your external devices all connect. All three, not just the one you were watching.
flowchart TD A["Mosquitto and EMQX
both want port 1883"] --> B["1 · Disable the Mosquitto add-on
to free up 1883"] B --> C["2 · Point existing devices and integrations
at EMQX — homeassistant, 1883"] C --> D["3 · Create the same MQTT users in EMQX,
carry retained messages and ACL over"] D --> E["4 · Start EMQX and confirm HA, Z2M
and external devices all connect"]
What you gain is worth stating plainly, because “why bother” is a fair question. Mosquitto has no graphical interface, no client list, no Rule Engine and no built-in WebSocket. EMQX gives you all four in the Dashboard, and that is exactly what EMQX adds over Mosquitto.
Eight symptoms and what to check for each
Four of these come from the bridging side and four from the Home Assistant side. In both halves, the answer is nearly always something ordinary rather than something deep.
| Symptom | What to check |
|---|---|
| The Source receives nothing from the remote broker | Check that the Connector state is Connected, that the subscribe Topic and QoS are right, that the wildcards are correct, and that something really is publishing on the remote broker. |
| Duplicate data with a cluster or a connection pool | Switch to a shared subscription, $share/<group>/topic, so several bridge clients do not each receive the same message. |
| The written-back messages never arrive locally | A Source only brings the message in; it takes a separate Republish action to write it back onto a local topic. Check that the action was added and that the rule was actually created. |
| A SQL field comes back empty | Check that the rule's FROM is the right $bridges/mqtt:<name>, and that the name you put in matches the Source's name. |
| The HA MQTT integration will not connect | Check that EMQX is running, that Address is homeassistant or the correct host address, that the port is 1883, and that you created the account in EMQX (authentication). |
| Discovery brings in no devices | Check the discovery prefix (homeassistant/) and whether birth and will are working, whether the device published a discovery message at all, and whether Home Assistant has been upgraded. |
| Running alongside Mosquitto fails | The two brokers are fighting over the same 1883. Stop Mosquitto first — or move the EMQX listener to another port — then start the other side. |
| Z2M cannot reach EMQX | The broker host Z2M uses has to work (homeassistant or the add-on slug), and check that Z2M is using the account you created in EMQX, not the old Mosquitto one. |
The eight that come up most
What is the difference between a Source and a Sink?
Does an MQTT broker bridge need a cluster?
Can I connect to the remote broker with a fixed client ID?
Does an inbound message have to go through Republish?
Does Home Assistant need an MQTT broker in place first?
homeassistant, 1883, username and password. EMQX is the new broker.I run Mosquitto today — is migrating to EMQX a lot of work?
Where do I set the discovery prefix and the status topic?
homeassistant/, and you can name the birth and will topics yourself.Can EMQX and Mosquitto run side by side?
Where to go from here
Everything is connected. Now watch it.
With devices, bridges and Home Assistant all on your broker, the interesting question stops being “does it connect” and becomes “what is it doing right now.” Part 7 moves into operations: the client list, the monitoring pages, what happens to messages you cannot see, and where the configuration actually lives.
Open the full guidePart 6 of the WoowTech EMQX Complete Guide series on the Apporo blog.
Adapted from the WoowTech EMQX Complete Guide, produced by WoowTech and released under CC BY 4.0. This adaptation is published by Apporo under the same licence.
Light · Air · Water · Control · apporo