Skip to content

Bitcoin accepted at checkout  |  Ships from Montreal, QC, Canada  |  Expert support since 2016

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 mosquitto
    mosquitto-clients gives you mosquitto_sub and mosquitto_pub for 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 to false when 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”; with allow_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 topicroot (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 (#)TypeWhat the schema saysPrivate-broker setting
enabled (1)boolTurns 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)stringSame 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)messageMapReportSettings: 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.