Skip to main content

MQTT Topic Structure and Packet Format

Understanding Meshtastic's MQTT topic structure and packet encoding lets you build integrations, parse data, and troubleshoot gateway connectivity issues.

Topic Structure

Meshtastic publishes to MQTT topics using this hierarchy:

msh/{region}/{protocol_version}/{channel_type}/{channel_name}/{node_id}

Examples:
msh/US/2/e/LongFast/!ab12cd34   # Encrypted packet from node ab12cd34
msh/US/2/json/LongFast/!ab12cd34 # JSON-decoded packet (if node has JSON enabled)

Where:
  msh/       - Meshtastic prefix
  US/        - Region code (US, EU, etc.)
  2/         - Protocol version
  e/         - Encrypted (default)
  json/      - JSON decoded (optional, if JSON output enabled on gateway)
  LongFast/  - Channel name
  !ab12cd34  - Source node ID

Subscribing to All Traffic

# Subscribe to all Meshtastic packets from all US nodes:
mosquitto_sub -h mqtt.meshtastic.org -u meshdev -P large4cats   -t "msh/US/2/e/#" -v

# Subscribe to a specific channel only:
mosquitto_sub -h mqtt.meshtastic.org -t "msh/US/2/e/CommunityMesh/#" -v

# Subscribe to JSON-decoded packets (if gateway has JSON enabled):
mosquitto_sub -h localhost -t "msh/US/2/json/#" -v

Packet Format

Each MQTT message payload is a protobuf-encoded ServiceEnvelope containing:

  • packet — The MeshPacket (encrypted payload + routing info)
  • channel_id — Channel name (e.g., "LongFast")
  • gateway_id — Node ID of the gateway that published to MQTT

Enabling JSON Output on a Gateway Node

# Enable JSON output in addition to (not instead of) protobuf:
meshtastic --set mqtt.json_enabled true

# JSON packets are published to: msh/US/2/json/{channel}/{node_id}
# JSON payload example:
{
  "from": 2881537332,
  "to": 4294967295,
  "channel": 0,
  "id": 123456789,
  "rx_time": 1712000000,
  "hop_limit": 3,
  "payload": {
    "text": "Hello mesh!"
  }
}

Decoding Protobuf Packets in Python

import paho.mqtt.client as mqtt
from meshtastic.mesh_pb2 import ServiceEnvelope
from meshtastic.portnums_pb2 import PortNum
import base64

def on_message(client, userdata, msg):
    try:
        se = ServiceEnvelope()
        se.ParseFromString(msg.payload)
        packet = se.packet
        print(f"From: !{packet.from_:08x}")
        print(f"To: !{packet.to:08x}")
        print(f"Channel: {se.channel_id}")
        # Decrypt and decode based on portnum for full payload
    except Exception as e:
        print(f"Parse error: {e}")

client = mqtt.Client()
client.username_pw_set("meshdev", "large4cats")
client.on_message = on_message
client.connect("mqtt.meshtastic.org", 1883)
client.subscribe("msh/US/2/e/#")
client.loop_forever()