Skip to Content

Messages from somebody else's broker, and Home Assistant on yours

the way back in
EMQX Guide · Part 6

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.

2 directions
Ingress brings messages in, egress sends them out — and one Connector can serve both at once
7 fields
What an MQTT Source hands to your rule SQL, from topic through to message_received_at
1 port
Port 1883. Mosquitto and EMQX both want it, and only one of them can have it
A Sink out, a Source in

Not 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.

In plain terms

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.

TermPlain EnglishIn one line
Sourceinput sourceWhere external data enters EMQX (ingress)
Sinkoutput targetWhere EMQX data goes out to an external system (egress)
MQTT Broker BridgeMQTT bridgeMoves messages between two MQTT brokers
IngressinboundBrings messages from a remote broker into EMQX
EgressoutboundPublishes 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
Out and in, on one ConnectorThe upper lane is ingress and it has four boxes; the lower lane is egress and has three. That extra box is the Republish action, and it exists only on the way in — nothing equivalent is needed on the way out.
The one thing to take away before you build anything: a Source does not publish to a local topic on its own. It brings the external message into the rule's processing pipeline and stops there. For a local client — or Home Assistant — to receive it, you add a Republish action. Nearly every “my bridge does nothing” report comes down to this.
Building the bridge

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.

  1. Step 1

    Create the MQTT Broker Connector

    In the Dashboard go to Integration → Connectors → Create and pick MQTT Broker. Name it my_mqtt_bridge and set the server to:

    broker.emqx.io:1883

    If the remote broker requires authentication, fill in the credentials here. Then click Create.

  2. 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 plain f/#.

  3. 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.

  4. 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 remote f/1 becomes a local sub/f/1: the prefix is yours, the tail is theirs.

  5. 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 to f/1 on the remote broker, and it should arrive locally on sub/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"]
One message, all the way throughFive boxes top to bottom, one straight line with no branches. The fourth box is the one people leave out, and without it the chain stops at the third.
What a Source hands you

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 above
In plain terms

Four 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:

FieldWhat it means
topicThe topic of the original message
serverThe address of the source broker
payloadThe message payload
qosThe QoS of the message
retainWhether the message is retained
pub_propsMQTT 5.0 message properties (user property and so on)
message_received_atThe 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.

There is no fixed client ID here, and that is deliberate. On a cluster, or across several nodes, a fixed MQTT client ID would collide between them — two clients presenting the same ID to the same broker is a fight neither wins. An MQTT broker bridge therefore does not offer a fixed client ID; EMQX generates a unique one for you. Reconnecting after a drop is also unreliable with a shared fixed ID, so this is not a restriction worth working around.
Home Assistant's broker

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.

  1. 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.

  2. 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.

  3. Step 3

    Fill in the broker connection details

    Four fields, and they are the whole configuration:

    Broker — homeassistant (or localhost)
    Port — 1883
    Username — the account you created in step 1
    Password — its password
  4. 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.

  5. 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"]
Why the order is fixedSix boxes top to bottom, one straight line with no branches. The account has to exist in EMQX before Home Assistant has anything to type into Username, which is why the first two boxes are on the EMQX side.
Discovery, birth and will

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:

Birth MessageThe integration publishes an “I'm here” message the moment it comes online, so other subscribers know Home Assistant has connected.
WillThe integration registers a will. If Home Assistant and the broker lose the connection unexpectedly, the broker sends an “offline” notice on Home Assistant's behalf.
StatusBoth of those land on Home Assistant's status topic — homeassistant/status, for example — which is how everyone else, and your EMQX rules, can tell whether Home Assistant is online or offline.
In plain terms

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"]
Three things at the moment of connectionThree arrows leave the top box: the birth message on the left, the discovery subscription down the middle, and the will handed to the broker on the right. Only the middle and right branches continue — the birth message ends where it is drawn.
TermPlain EnglishIn one line
MQTT IntegrationHA's broker connectionThe integration HA uses to connect to an MQTT broker (EMQX)
Discoveryautomatic device setupHA adds the MQTT devices that announce themselves, without your help
Birth Messageonline announcementThe “I'm here” message the integration publishes when it comes online
Status Topiconline/offline topicThe topic that says whether the integration is online or offline
Willoffline noticeThe notice the broker sends on the client's behalf when it drops offline unexpectedly
State Topicdevice state topicThe topic a device publishes its state updates on
Where these settings live: the discovery prefix and the broker status (birth and will) parameters are in the Home Assistant MQTT advanced settings. The default discovery prefix is homeassistant/, and you can name the birth and will topics yourself.
Zigbee2MQTT and leaving Mosquitto

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.

In plain terms

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:

  1. Step 1

    Disable your existing Mosquitto add-on

    This frees up 1883. Until it is done, nothing else in this list can succeed.

  2. Step 2

    Point your existing devices and integrations at EMQX

    The broker of everything currently talking to Mosquitto now becomes homeassistant, port 1883, with the EMQX account.

  3. 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.

  4. 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"]
The migration, in the order givenOne unbranched column: the top box is the constraint, and the four numbered boxes below it are the steps. Nothing here runs in parallel — step 4 is the only one that tells you whether the other three worked.

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.

Do not migrate everything on the same evening. ACLs and rules built up over a long time are the fiddly part of this. Move one kind of device across first, as a small trial, and let it run for a day before you bring the rest over.
When nothing arrives

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.

SymptomWhat 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.
Questions people ask

The eight that come up most

What is the difference between a Source and a Sink?
A Source is ingress (external → EMQX) and a Sink is egress (EMQX → external). One MQTT Connector can serve a Source and a Sink at the same time, and the traffic in and out is independent of each other.
Does an MQTT broker bridge need a cluster?
No. It does support clusters and connection pools, though; when several nodes or several clients connect at once, the official advice is to use a shared subscription to avoid duplicate messages.
Can I connect to the remote broker with a fixed client ID?
It is not advisable. With a cluster or a connection pool, several nodes sharing one client ID collide, and reconnecting after a drop is unreliable. An MQTT broker bridge does not offer a fixed client ID; EMQX generates a unique one for you.
Does an inbound message have to go through Republish?
Yes. A Source only brings the external message into the rule's processing pipeline; it does not publish to a local topic on its own. For a local client — or Home Assistant — to receive it, add a Republish action, or send it to a Sink.
Does Home Assistant need an MQTT broker in place first?
No. Once the broker is EMQX, the Home Assistant MQTT integration only has to point at EMQX — homeassistant, 1883, username and password. EMQX is the new broker.
I run Mosquitto today — is migrating to EMQX a lot of work?
It comes down to: stop Mosquitto → let EMQX take 1883 → point the integration and Z2M at EMQX → sync the users and the ACL. ACLs and rules built up over a long time are the fiddly part, so migrate one kind of device first as a small trial.
Where do I set the discovery prefix and the status topic?
In the Home Assistant MQTT advanced settings, where you adjust the discovery prefix and the broker status (birth and will) parameters. The default discovery prefix is homeassistant/, and you can name the birth and will topics yourself.
Can EMQX and Mosquitto run side by side?
Not both on 1883, and both default to it. The Woow EMQX documentation states plainly that it cannot run at the same time as Mosquitto. Either switch over for good, or move one side's listener to a different port.
Next

Where to go from here

keep going

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 guide

Part 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

in EMQX
Rules, actions and the wire out to everything else