wolfMQTT Broker

June 8, 2026 ยท View on GitHub

wolfMQTT includes a lightweight MQTT broker suitable for embedded and resource-constrained environments. It serves both MQTT v3.1.1 and v5.0 clients, with optional TLS via wolfSSL, optional WebSocket transport, and optional encrypted persistence. The broker uses non-blocking sockets driven by a single select() loop, so it runs without threads.

Features

  • QoS 0, QoS 1, and QoS 2 publish/subscribe (full QoS 2 flow with PUBREC/PUBREL/PUBCOMP)
  • Retained messages
  • Last Will and Testament (LWT), including v5 Will Delay Interval
  • Wildcard subscriptions (+ and #)
  • Username/password authentication
  • MQTT v5 ordering and Receive Maximum (per-subscriber inflight shaping)
  • TLS support (requires wolfSSL with --enable-tls)
  • WebSocket / secure WebSocket transport (requires libwebsockets; see the WebSocket section of the main README.md)
  • Clean session handling with subscription persistence
  • Keep-alive monitoring with automatic client disconnect
  • Unique client ID enforcement (existing session takeover)
  • Optional on-disk persistence of sessions, subscriptions, retained messages, and offline queues, with optional AES-GCM encryption-at-rest
  • Static memory mode (WOLFMQTT_STATIC_MEMORY) for zero-malloc operation

Quick start

With autotools:

./configure --enable-broker
make
./src/mqtt_broker -p 1883

With CMake:

cmake .. -DWOLFMQTT_BROKER=yes
cmake --build .

For TLS:

./configure --enable-broker --enable-tls
make
./src/mqtt_broker -p 8883 -t -A ca-cert.pem -K server-key.pem -c server-cert.pem

Run ./src/mqtt_broker -h to see the options compiled into your build.

Command-line options

usage: mqtt_broker [-p port] [-v level] [-u user] [-P pass]
                   [-t] [-s port] [-V ver] [-c cert] [-K key] [-A ca]
                   [-w port] [-D dir] [-E source]
OptionAvailable whenDescription
-p <port>alwaysPlain (non-TLS) port (default: 1883)
-v <level>alwaysLog level: 1=error, 2=info (default), 3=debug
-u <user>auth buildUsername for authentication
-P <pass>auth buildPassword for authentication
-tTLS buildEnable the TLS listener
-s <port>TLS buildTLS port (default: 8883)
-V <ver>TLS buildTLS version: 12=TLS 1.2, 13=TLS 1.3 (default: auto)
-c <file>TLS buildServer certificate file (PEM)
-K <file>TLS buildServer private key file (PEM)
-A <file>TLS buildCA certificate for mutual TLS (PEM)
-w <port>WebSocket buildWebSocket listen port (enables WebSocket)
-D <dir>persist buildPersistent storage directory (enables persistence; default /var/lib/wolfmqtt)
-E <source>encrypt + dev-key buildEncryption key source. Only dev is recognized, selecting the development hard-coded key. NOT FOR PRODUCTION.

Build options

All broker features are enabled by default and can be disabled at build time to reduce code and memory footprint on constrained platforms.

FeatureAutotoolsCMakeDefine
Broker support--enable-broker-DWOLFMQTT_BROKER=yesWOLFMQTT_BROKER
Retained messages--disable-broker-retained-DWOLFMQTT_BROKER_RETAINED=noWOLFMQTT_BROKER_NO_RETAINED
Last Will and Testament--disable-broker-will-DWOLFMQTT_BROKER_WILL=noWOLFMQTT_BROKER_NO_WILL
Wildcard subscriptions--disable-broker-wildcards-DWOLFMQTT_BROKER_WILDCARDS=noWOLFMQTT_BROKER_NO_WILDCARDS
Authentication--disable-broker-auth-DWOLFMQTT_BROKER_AUTH=noWOLFMQTT_BROKER_NO_AUTH
Logging--disable-broker-log-DWOLFMQTT_BROKER_LOG=noWOLFMQTT_BROKER_NO_LOG
Plain-text listener--disable-broker-insecure-DWOLFMQTT_BROKER_INSECURE=noWOLFMQTT_BROKER_NO_INSECURE

The maximum QoS the broker negotiates is capped by --enable-max-qos=<0,1,2> (default 2). Setting it to 1 or 0 compiles out the QoS 2 state machine and shrinks the broker.

Static memory tuning

When built with WOLFMQTT_STATIC_MEMORY, the broker uses fixed-size arrays instead of dynamic allocation. The limits below can be overridden via CFLAGS at build time.

MacroDefaultDescription
BROKER_MAX_CLIENTS8Maximum concurrent client connections
BROKER_MAX_SUBS32Maximum total subscriptions across all clients
BROKER_MAX_RETAINED16Maximum retained messages
BROKER_MAX_CLIENT_ID_LEN64Maximum client ID length
BROKER_MAX_USERNAME_LEN64Maximum username length
BROKER_MAX_PASSWORD_LEN64Maximum password length
BROKER_MAX_FILTER_LEN128Maximum subscription filter length
BROKER_MAX_TOPIC_LEN128Maximum topic name length
BROKER_MAX_PAYLOAD_LEN4096Maximum retained message payload
BROKER_MAX_WILL_PAYLOAD_LEN256Maximum LWT payload
BROKER_MAX_PENDING_WILLS4Maximum queued pending wills
BROKER_MAX_INBOUND_QOS216Concurrent inbound QoS 2 packet IDs per client
BROKER_RX_BUF_SZ4096Per-client receive buffer size
BROKER_TX_BUF_SZ4096Per-client transmit buffer size
BROKER_TIMEOUT_MS1000select() timeout
BROKER_LISTEN_BACKLOG128Listen queue depth

With dynamic memory the per-subscriber inflight window is derived at runtime, bounded by BROKER_MIN_INFLIGHT_PER_SUB (default 8) and BROKER_MAX_INFLIGHT_PER_SUB. Define BROKER_MAX_INFLIGHT_PER_SUB=1 to force strict serial delivery (one inflight QoS 1/2 message per subscriber).

Persistence

Build with --enable-broker-persist to persist sessions, subscriptions, retained messages, and offline queues across restarts. The persistence layer is hook-based: a default POSIX backend stores records as files under the directory given with -D (default /var/lib/wolfmqtt). Embedded targets can supply their own storage backend through MqttBroker_SetPersistHooks().

MacroDefaultDescription
BROKER_MAX_PERSIST_SESSIONS64Persistent sessions retained across restarts
BROKER_MAX_OFFLINE_MSGS_PER_SUB32Offline queue depth per session
WOLFMQTT_BROKER_PERSIST_SCHEMA_VER3On-disk record schema version

Encryption at rest

Add --enable-broker-persist-encrypt (requires --enable-broker-persist) to wrap persisted records with wolfCrypt AES-GCM. The key is provided by a derive_key callback that real deployments install via MqttBroker_SetPersistHooks() before starting the broker.

For development and CI only, the CLI can link a fixed-pattern derive_key hook so the AES-GCM round-trip can be exercised without external key management. This is NOT a configure option -- define the macro through CFLAGS:

CFLAGS="-DWOLFMQTT_BROKER_PERSIST_ENCRYPT_DEV_KEY" \
  ./configure --enable-broker --enable-broker-persist --enable-broker-persist-encrypt
make
./src/mqtt_broker -p 1883 -D ./state -E dev

The dev key is a trivially-recoverable hard-coded pattern. Never define WOLFMQTT_BROKER_PERSIST_ENCRYPT_DEV_KEY in a production build, and never pass -E dev in production -- doing so substitutes the fixed key for real key management. Production builds omit the macro entirely, so the -E option and the dev hook are not present in the binary.

Testing

The repository ships an end-to-end broker test harness:

./scripts/broker.test

It builds the client examples (examples/pub-sub/mqtt-pub, examples/pub-sub/mqtt-sub) and mosquitto-based checks against the wolfMQTT broker, covering QoS flows, retained messages, wildcards, persistence round-trips, and AES-GCM encryption (when the dev-key hook is linked). Tests that depend on features not present in the current build are reported as SKIP.

The CONNECT-handler unit test (tests/test_broker_connect) is part of make check and exercises the broker packet path with a mock network layer.

Limitations

The wolfMQTT broker targets embedded and edge use cases. It is intentionally smaller in scope than full-featured server brokers such as Mosquitto or EMQX: there is no clustering, no bridging, no plugin/ACL framework, and no dynamic configuration reload. For large-scale or feature-rich deployments use a dedicated server broker; for a small, auditable, optionally-TLS broker that runs without threads or a heap, wolfMQTT is a good fit.