MQTT Broker Bridges: Prevent Topic-Remapping Loops Between Edge and Plant Brokers
Review a broker bridge as a directed graph of broker-and-topic states. For every forwarding rule, compute the destination topic after prefix removal and addition, then ask whether another rule can send it back into the original export space. Distinct ingress and egress prefixes make that analysis easier and reduce reliance on implementation-specific loop suppression.
This guide pins the bridge topic-remapping contract in Eclipse Mosquitto 2.0.20’s configuration manual. An original bounded reachability model was executed. No live bridge loop was injected, and the model does not implement Mosquitto’s private bridge signaling, QoS processing or retained-message handling.
Expand each rule into actual source and destination names
A Mosquitto bridge topic rule specifies a pattern, direction, QoS and optional local and remote prefixes. Outgoing traffic matches the local prefix plus pattern, removes the local prefix and adds the remote prefix. Incoming traffic performs the reverse mapping from the remote prefix plus pattern.
Direction is relative to the broker containing that bridge configuration. Write the broker names beside every rule so “in” and “out” do not become ambiguous when comparing configurations from two machines.
Keep a ledger of the effective source filter, source broker, strip prefix, add prefix and destination broker. Include every bridge connection, application republisher and protocol adapter that can return a message to the graph. A loop can cross an application even when each broker configuration looks simple in isolation.

Use disjoint namespaces for different directions
For a hypothetical edge07 gateway, an outbound telemetry rule can map local outbox/telemetry/# into plant plant/edge07/telemetry/#. An inbound command rule can map plant plant/edge07/commands/# into local inbox/commands/#.
The following fragment illustrates the pinned syntax. It was reviewed against the manual but was not loaded into a live bridge; connection address, authentication and deployment authorization are intentionally outside this example.
# Illustrative Mosquitto 2.0.20 fragment; not executed as configuration.
topic telemetry/# out 1 outbox/ plant/edge07/
topic commands/# in 1 inbox/ plant/edge07/
After inbound remapping, a command enters inbox rather than outbox. It therefore does not match the outbound telemetry source filter. This is a property of the declared names and rules, not an assumption that the broker recognizes the business meaning of “command.”
Prefixes are literal text. Include separators deliberately: edge07/ and edge07 produce different concatenations. Use the documented empty-prefix marker when an empty prefix is intended rather than relying on omitted arguments to mean the same thing.
Demonstrate the potential cycle
The bad logical fixture has two effective forwarders. The first sends edge outbox/telemetry/t1 to plant plant/edge07/telemetry/t1. The second sends that plant topic back to edge outbox/telemetry/t1.
The model detects the repeated broker-and-topic state after two edges. If both effective forwarding paths admit the returned message, it can circulate again. This demonstrates a configuration-level risk; it does not assert that Mosquitto’s default private bridge behavior will forward every such return.
The corrected fixture removes the reverse telemetry export and admits only the separate command namespace in the reverse direction. The telemetry walk stops at the plant, and a command walk stops in the edge inbox. Both termination points were asserted.
Do not promote loop detection into an architecture guarantee
The pinned manual says try_private attempts to identify the connection as a bridge. When supported, it makes loop detection more effective and helps retained-message propagation. It defaults to true, but not every remote broker supports the feature.
That is not a portable promise that every multi-broker graph is loop-free. Inventory which peers recognize bridge signaling, which links act as ordinary clients and which applications republish received payloads under new topics.
Do not disable private signaling merely to make a connection succeed and assume nothing else changed. Requalify loop behavior and retained propagation under the actual interoperating broker versions. The manual itself warns that topic mappings can create endless forwarding loops.
Separate loops from other repeated deliveries
One application event can arrive more than once through overlapping subscriptions, QoS retransmission or independent routes. A loop diagnosis needs evidence of repeated traversal through the forwarding graph, not just equal payload bytes at one consumer.
Use a synthetic event identifier in a harmless test payload and record broker, connection, topic before and after rewrite, and local observation order. MQTT Packet Identifiers are scoped to exchanges and can change at each hop; they are not a stable cross-bridge event identity.
Preserve the original topic and ingress classification where the application contract allows it. An origin field can aid diagnosis, but adding one does not stop a loop unless every relevant forwarder actually enforces the rule.
Test with bounded injection and a stop condition
- Export the complete mapping ledger and expand representative topics through every rule.
- Find repeated broker-topic states and topic growth, such as prefixes repeatedly appended on each pass.
- In an isolated test deployment, start with one-way forwarding and publish a single uniquely identified telemetry fixture.
- Enable the intended reverse direction and verify that the incoming namespace does not re-enter an export rule.
- Exercise retained startup data and reconnect only after the basic directional graph is understood.
- Set explicit observation, message-count and resource limits, with a prepared way to stop the test forwarders.
Do not deliberately create a forwarding storm on a production plant broker. A finite logical walk is the safer first test. Live validation is still needed for private bridge behavior, retained flags and middleware republishers that the model does not contain.
Keep configuration changes reviewable
When a prefix or direction changes, recompute the graph and retain negative test cases. An old remote subscription or a second overlooked bridge can preserve an unwanted route after the visible local rule changes; check the documented session and cleanup behavior during migration.
Acceptance means every permitted message class reaches a named terminal consumer space, while no effective route returns it to an eligible export state. The deliverable is the mapping graph and its tested boundary topics, not merely a pair of brokers that connect successfully.