Self-Host a Private Meshtastic MQTT Broker with Mosquitto
Quick answer
To keep Meshtastic MQTT traffic off the public mqtt.meshtastic.org broker, run your own Mosquitto broker: a four-line mosquitto.conf (listener 1883, allow_anonymous false, password_file, acl_file), one mosquitto_passwd user per gateway, an ACL scoped to your msh/# root topic, then point each node’s MQTT module address, username and password at it.
Our Meshtastic MQTT guide covers the concepts: what the MQTT module bridges, what leaks through it, and why the default public broker puts your mesh’s metadata in a shared pool. This page is the self-host companion — the actual broker build. The audience is someone comfortable flashing a radio but new to running a server, so every step is spelled out. When you are done, your mesh’s internet bridge terminates on hardware you control: no shared broker, no shared credentials, no third party reading your topic tree. It is the same instinct as running your own Bitcoin node — the sovereignty stack works because every layer of it is yours.
Sources: Meshtastic module fields are cited with their literal field numbers from
meshtastic/protobufs → module_config.proto (MQTTConfig) and
channel.proto; topic layout is quoted from meshtastic/firmware → src/mqtt/MQTT.h;
Mosquitto directives are from the mosquitto.conf(5) and mosquitto_passwd(1) man pages on
mosquitto.org — all as of 2026-07-22.
What you need
- An always-on box. A Raspberry Pi, a home server, or a small VPS — anything that runs Linux and stays up. MQTT is a lightweight publish/subscribe protocol; the broker’s load from a hobby mesh is tiny.
- Mosquitto. The open-source MQTT broker from the Eclipse Mosquitto project. On Debian or
Ubuntu (including Raspberry Pi OS):
sudo apt install mosquitto mosquitto-clients sudo systemctl enable mosquittomosquitto-clientsgives youmosquitto_subandmosquitto_pubfor testing. - At least one Meshtastic node with internet access (Wi-Fi, Ethernet, or the phone proxy) to act as the gateway between LoRa and your broker.
Step 1 A minimal locked-down mosquitto.conf
Create /etc/mosquitto/conf.d/mesh.conf:
# /etc/mosquitto/conf.d/mesh.conf
listener 1883
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl
Four directives, each doing one job — all from the mosquitto.conf(5) man page:
listener 1883— “Listen for incoming network connection on the specified port.” 1883 is Mosquitto’s default MQTT port. Without an explicit listener, current Mosquitto only accepts connections from the local machine — defining one is what opens the broker to your gateway nodes, which is exactly why the next three lines must come with it.allow_anonymous false— “determines whether clients that connect without providing a username are allowed to connect.” The man page notes it already defaults tofalsewhen listeners are defined; we state it explicitly so the intent survives config edits.password_file— “If defined, the contents of the file are used to control client access to the broker”; withallow_anonymous false, “only users defined in this file will be able to connect.”acl_file— “If defined, the contents of the file are used to control client access to topics on the broker.” Crucially: “If this parameter is defined then only the topics listed will have access” — the ACL file is default-deny.
Current Mosquitto documentation suggests the newer mosquitto_password_file and
mosquitto_acl_file plugins as the forward path for per-listener control; the classic
password_file / acl_file directives above still work and are the simplest correct setup
for a single-listener private broker.
Step 2 Create broker users with mosquitto_passwd
# first user — -c CREATES the file (and OVERWRITES it if it exists)
sudo mosquitto_passwd -c /etc/mosquitto/passwd meshgate
# additional users — no -c, or you wipe the file
sudo mosquitto_passwd /etc/mosquitto/passwd dashboard
# remove a user
sudo mosquitto_passwd -D /etc/mosquitto/passwd dashboard
Each command prompts for the password interactively. The man page warns against the -b batch flag
for routine use because “the password will be visible on the command line and in command history.”
Passwords are stored hashed (current Mosquitto defaults to argon2id), and usernames must not contain
a colon. One username per gateway node is a sane baseline — if a device is lost, you revoke that one credential.
Step 3 Scope the ACL to your root topic
Meshtastic publishes everything under a root topic — root (field 8 of
MQTTConfig), whose schema comment reads: “The root topic to use for MQTT messages. Default is
‘msh’. This is useful if you want to use a single MQTT server for multiple meshtastic networks and
separate them via ACLs” — which is precisely what this file does. Create /etc/mosquitto/acl:
# /etc/mosquitto/acl
# gateway nodes: full access to the mesh namespace, nothing else
user meshgate
topic readwrite msh/#
# read-only consumer (dashboard, logger)
user dashboard
topic read msh/#
Because a defined ACL file is default-deny, these users can touch only msh/# — a
compromised credential cannot wander into other topic trees. Access types are read,
write, readwrite and deny, and topics accept the usual + and
# wildcards. Running two separate meshes on one broker? Give each its own root on the
nodes (say msh-north and msh-south) and its own user +
topic readwrite msh-north/# block here. The man page also supports pattern rules with
%u (username) substitution for larger multi-tenant setups. Then restart:
sudo systemctl restart mosquitto
Step 4 Optional: TLS on port 8883
On a trusted LAN, plain 1883 with passwords and ACLs is a reasonable start. The moment the broker is reachable
across the internet, add TLS. Per the man page, certfile and keyfile “must be
present to enable certificate based TLS encryption” on a listener:
# append to /etc/mosquitto/conf.d/mesh.conf
listener 8883
certfile /etc/mosquitto/certs/fullchain.pem
keyfile /etc/mosquitto/certs/privkey.pem
8883 is the conventional MQTT-over-TLS port. The certificate pair can come from Let’s Encrypt or your own
CA; cafile is only needed if you additionally want the broker to verify client certificates.
Nodes connecting to this listener set tls_enabled (below).
Step 5 Point your nodes at the broker
These are the Meshtastic MQTT module settings, with their literal field numbers from
module_config.proto → MQTTConfig. Set them from the Meshtastic app or CLI on each
gateway node:
| Field (#) | Type | What the schema says | Private-broker setting |
|---|---|---|---|
enabled (1) | bool | Turns the module on; the node “will normally attempt to gateway any channels that are marked as is_uplink_enabled or is_downlink_enabled.” | true on gateway nodes only. |
address (2) | string | “The server to use for our MQTT global message gateway feature. If not set, the default server will be used” — i.e. the public broker. | Your broker’s hostname or IP. Leaving it empty is what sends traffic to mqtt.meshtastic.org. |
username (3) | string | “MQTT username to use (most useful for a custom MQTT server). If using a custom server, this will be honoured even if empty.” | The mosquitto_passwd user for this node. |
password (4) | string | Same honouring rule as username. | That user’s password. |
encryption_enabled (5) | bool | “Whether to send encrypted or decrypted packets to MQTT. This parameter is only honoured if you also set server.” | true — keep channel payloads encrypted at rest on your broker. |
json_enabled (6) | bool | “Deprecated: JSON packet support on MQTT was removed, and this field is ignored.” | Leave off — see the JSON note below. |
tls_enabled (7) | bool | “If true, we attempt to establish a secure connection using TLS.” | true if you built the 8883 listener; off for plain LAN 1883. |
root (8) | string | “The root topic to use for MQTT messages. Default is ‘msh’.” | Leave msh, or set a custom root that matches your ACL. |
proxy_to_client_enabled (9) | bool | “If true, we can use the connected phone / client to proxy messages to MQTT instead of a direct connection.” | Useful when the node itself has no Wi-Fi/Ethernet — the phone app carries the broker connection. |
map_reporting_enabled (10) | bool | “If true, we will periodically report unencrypted information about our node to a map via MQTT.” | Off is the private default — this report is unencrypted by design. |
map_report_settings (11) | message | MapReportSettings: publish_interval_secs (1), position_precision (2, “default of 32 is full precision”), should_report_location (3). | Only relevant if you enable map reporting on your own broker; keep position_precision coarse. |
Step 6 Flip uplink/downlink per channel
The module alone bridges nothing. Each channel carries two switches in
channel.proto → ChannelSettings: uplink_enabled (field 5 — mesh messages
are sent out through any gateway node) and downlink_enabled (field 6 — “messages seen on the
internet will be forwarded to the local mesh”). Both default to off. Enable them only on the channels you
actually want bridged — a channel with both off never touches your broker at all.
Verify it works
From any machine that can reach the broker, subscribe with an authorized user and watch packets arrive:
mosquitto_sub -h your.broker.example -u dashboard -P 'the-password' -t 'msh/#' -v
Send a text message on an uplink-enabled channel and you should see topics appear. The layout is defined in
meshtastic/firmware → src/mqtt/MQTT.h: encrypted protobuf packets publish under
/2/e/ (“msh/2/e/CHANNELID/NODEID” in the source comment) and map reports under
/2/map/, each prefixed by your root topic. The payloads on the /2/e/ path are raw
MeshPacket protobufs — our MeshPacket field reference
documents every field if you want to decode them. Two useful negative tests: connect with no credentials
(must be refused) and subscribe to a topic outside msh/# with a scoped user (must stay silent).
JSON note. As of 2026-07-22, the protobuf
schema marks json_enabled deprecated — “JSON packet support on MQTT was removed, and this field
is ignored” — while the firmware source still contains a /2/json/ topic path. Treat JSON output
as on its way out: build integrations on the protobuf /2/e/ path, not on JSON topics.
Why this is the sovereign default
The public broker is a fine community amenity, but every packet you uplink to it lands in someone else’s topic tree, readable under shared credentials. A private Mosquitto broker inverts that: your gateway, your credentials, your ACL, your disk. Pair it with Store & Forward for offline message history and you have an internet bridge and an answering machine that both live on hardware you own — the mesh-layer equivalent of running your own node instead of trusting someone else’s. For what the bridge exposes and when to use it at all, read the MQTT concepts guide; for the radio side, see Meshtastic encryption and the mesh hub.
Related
Meshtastic over MQTT: concepts and trade-offs (the companion to this page) · Store & Forward reference · MeshPacket & Data field reference · Meshtastic node roles · LoRa regions and channels.
Credit: Meshtastic and its MQTT module are built by the Meshtastic project (GPL-3.0), with the module schema in meshtastic/protobufs. Mosquitto is the Eclipse Mosquitto project’s open-source broker; directives above are from its official man pages. This page stands on both.
Related products, repair, and setup paths
- Bitcoiner sovereignty hub
- the plebs sovereign stack
- Nostr for Bitcoiners
- run your own Nostr relay
- getting started with Meshtastic
- Bitcoin over Meshtastic mesh networks
- open-source hardware tools directory
- off-grid Bitcoin mining
Last reviewed July 22, 2026.
