Sources and data import
A Source is the entry point that brings messages from an external MQTT broker back into your own EMQX; pair it with a republish action and those external messages get written back into EMQX, which is how you bridge across brokers.
Why this matters
Not every device connects to your EMQX. You may have a Zigbee gateway or a cloud platform that already publishes its data to another MQTT broker. To get those external messages into your EMQX, and from there into a rule or into Home Assistant, you need a way in — and that is a Source.
The Sink in Chapter 11 sends data out; this chapter goes the other way, into data import: an MQTT Source collects data from a remote broker, and a republish action (or a rule) writes those external messages back onto a topic your local EMQX can use.
Core concepts
Data bridging between MQTT brokers (many people call it an MQTT broker bridge, and the EMQX 5.x documentation calls it MQTT Broker Data Integration) lets EMQX connect to another MQTT service as a client and exchange messages in both directions:
- Egress (Sink): publishes messages from your local EMQX to a chosen topic on the remote broker.
- Ingress (Source): subscribes to a topic on the remote broker and feeds what it receives back into your local EMQX.
Both share the same Connector (Chapter 11). One connection can carry several bridge rules, each with its own topic mapping and transformation. For a local client to read what a Source brings in, you normally add a republish action that writes it back locally.
Terms at a glance
| 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 |
Hands-on
Following the official tutorial: bridge what a remote broker (broker.emqx.io) receives on f/# onto your local sub/#.
Create the MQTT Broker Connector
In the Dashboard go to Integration → Connectors → Create and pick MQTT Broker. Name it
my_mqtt_bridge, set the server tobroker.emqx.io:1883(fill in the credentials if the remote broker requires authentication), then click Create.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, choose the Connector, then set the subscribe Topic (
$share/1/f/#, for example) and the QoS.Check the rule SQL
Once the Source is added, the rule SQL becomes
SELECT * FROM "$bridges/mqtt:my_source"on its own, which says the data source is this MQTT broker bridge.Add the Republish action
Switch to the "Action Outputs" tab, click + Add Action and pick Republish. Set Topic to
sub/${topic}, QoS to${qos}and Payload to${payload}.Create it and verify
Click Create to finish the rule. Subscribe to
sub/#locally, publish a message tof/1on the remote broker, and it should arrive locally onsub/f/1.
MQTT Source and the $bridges syntax
Two things to watch when you create an MQTT Source:
- The subscribe topic accepts the
+and#wildcards, so one Source can pick up a whole family of remote topics. - Use a shared subscription with a cluster or a connection pool: when EMQX runs as a cluster, or the Connector has a connection pool open, several clients subscribe to the same topic at once and each of them receives the message. The official advice is to spread that load with
$share/<group>/topic(for example$share/1/f/#).
The fields a Source brings in, for use in the rule SQL, are:
| 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 uses $bridges/mqtt:<name> as its data source, where <name> is the name of the Connector/Source.
Bridging across brokers and writing back to EMQX
The egress side is simple: 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}, for example, 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.
Ingress write-back is what a Source is for: it pulls the messages it subscribed to on the remote broker into a rule, but it does not publish them locally by itself — you have to add a Republish action to write them back onto a local topic. The official example uses sub/${topic}, so a remote f/1 lands on your sub/f/1, and a local client that subscribes to sub/# receives it.
To declare all of this in a config file instead, create the matching ingress (Source) and egress (Sink) bridges in the rule_engine and connector/bridges sections, mirroring the rule's SQL. On a cluster or across several nodes a fixed MQTT client ID would collide between them, which is why a fixed client ID is not supported here.
Troubleshooting
- 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 actually write it back onto a local topic. Check that the action was added and the rule created.
- A SQL field comes back empty: check that the rule's
FROMis the right$bridges/mqtt:<name>, and that the name you put in matches the Source's name.
FAQ
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.
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.