mqttv5 CLI Usage Guide

September 9, 2026 · View on GitHub

Complete reference for the mqttv5 command-line tool.

Overview

The mqttv5 CLI is a single binary that covers every common MQTT workflow: running a broker, publishing messages, subscribing to topics, benchmarking performance, and managing authentication credentials. All commands share a consistent set of connection, TLS, and authentication flags, so the patterns you learn for pub carry over to sub, bench, and beyond.

Global flags:

  • --verbose, -v - Enable verbose logging (MQTT5_VERBOSE)
  • --debug - Enable debug logging (MQTT5_DEBUG)

Quick Start

Start a broker, publish a message, and subscribe — all in three terminals:

mqttv5 broker --allow-anonymous

mqttv5 pub -t "hello/world" -m "Hello, MQTT!"

mqttv5 sub -t "hello/#" -v

Environment Variables

Every flag on the broker, pub, and sub subcommands can be set via environment variables. The naming convention is MQTT5_ prefix + upper-snake-case of the long flag name:

CLI FlagEnvironment VariableNotes
--host (pub/sub)MQTT5_HOSTBroker hostname to connect to
--host (broker)MQTT5_BINDTCP bind address(es)
--tls-host (broker)MQTT5_TLS_BINDTLS bind address(es)
--ws-host (broker)MQTT5_WS_BINDWebSocket bind address(es)
--tls-certMQTT5_TLS_CERT
--max-clientsMQTT5_MAX_CLIENTS
--non-interactiveMQTT5_NON_INTERACTIVE
--otel-endpointMQTT5_OTEL_ENDPOINT

Precedence

CLI flag > environment variable > default value.

When --config is provided to the broker, the config file takes over and other broker flags are ignored (existing behavior, unchanged).

Repeatable Flags

Flags that accept multiple values (--host, --tls-host, --ws-host, --ws-tls-host, --quic-host, --jwt-role-map, --jwt-trusted-role-claim) use comma-separated values when set via environment variables:

# These are equivalent:
mqttv5 broker --host 0.0.0.0:1883 --host [::]:1883
MQTT5_BIND="0.0.0.0:1883,[::]:1883" mqttv5 broker

On the CLI, repeated -H flags still work as before. The env var adds comma-splitting as an alternative.

Boolean Flags

Boolean flags (--allow-anonymous, --retain, --insecure, etc.) treat any non-empty env var value as true:

MQTT5_ALLOW_ANONYMOUS=true mqttv5 broker
MQTT5_ALLOW_ANONYMOUS=1 mqttv5 broker    # also works

Docker Usage

The Docker image sets MQTT5_NON_INTERACTIVE=true by default. All broker configuration can be done via env vars:

docker run -e MQTT5_BIND=0.0.0.0:1883 \
           -e MQTT5_ALLOW_ANONYMOUS=true \
           -e MQTT5_STORAGE_BACKEND=memory \
           -p 1883:1883 \
           mqttv5 broker

Discovery

Run --help on any subcommand to see the env var name for each flag:

mqttv5 broker --help   # shows [env: MQTT5_HOST=] etc.
mqttv5 pub --help
mqttv5 sub --help

Command Reference

mqttv5 broker

Start an MQTT v5.0 broker with support for multiple transports, authentication methods, and storage backends. The broker listens on one or more addresses and can serve TCP, TLS, WebSocket, and QUIC simultaneously.

The broker also supports a generate-config subcommand to produce a full example configuration file.

mqttv5 broker generate-config [--output FILE] [--format json|toml]

Broker Flags

FlagDescriptionDefault
--config, -c <FILE>Configuration file path (JSON format)None
--host, -H <ADDR>TCP bind address(es), can be specified multiple times0.0.0.0:1883, [::]:1883
--max-clients <N>Maximum concurrent clients10000
--allow-anonymousAllow anonymous connectionsNone (prompted if no auth configured)
--auth-password-file <FILE>Password file for authenticationNone
--acl-file <FILE>ACL file for authorizationNone
--auth-method <METHOD>Authentication method: password, scram, jwt, jwt-federatedpassword if auth file provided
--scram-file <FILE>SCRAM credentials file pathNone
--tls-cert <FILE>TLS certificate file (PEM format)None
--tls-key <FILE>TLS private key file (PEM format)None
--tls-ca-cert <FILE>TLS CA certificate for client verificationNone
--tls-require-client-certRequire client certificates (mTLS)false
--tls-host <ADDR>TLS bind address(es), can be specified multiple times0.0.0.0:8883, [::]:8883
--ws-host <ADDR>WebSocket bind address(es), can be specified multiple timesNone
--ws-tls-host <ADDR>WebSocket TLS bind address(es), can be specified multiple timesNone
--ws-path <PATH>WebSocket path/mqtt
--quic-host <ADDR>QUIC bind address(es), requires TLS cert/keyNone
--quic-delivery-strategy <S>QUIC server delivery strategy: control-only, per-topic, per-publishper-topic
--quic-early-dataEnable QUIC 0-RTT early datafalse
--storage-dir <DIR>Storage directory for persistence./mqtt_storage
--storage-backend <TYPE>Storage backend: memory or filefile
--no-persistenceDisable message persistencefalse
--session-expiry <SECS>Default session expiry interval in seconds3600
--max-qos <0|1|2>Maximum QoS level2
--keep-alive <SECS>Server keep-alive time in secondsNone
--response-information <STR>Response information sent to clients that request itNone
--no-retainDisable retained messagesfalse
--no-wildcardsDisable wildcard subscriptionsfalse
--no-sys-topicsDisable $SYS topic publishing (broker statistics)false
--sys-interval <DUR>$SYS topic publish interval (e.g., 10, 10s, 1m)10
--non-interactiveSkip interactive promptsfalse
Broker JWT Auth Flags
FlagDescriptionDefault
--jwt-algorithm <ALG>JWT algorithm: hs256, rs256, es256None
--jwt-key-file <FILE>JWT secret file (HS256) or public key file (RS256/ES256)None
--jwt-issuer <ISS>JWT required issuerNone
--jwt-audience <AUD>JWT required audienceNone
--jwt-clock-skew <SECS>JWT clock skew tolerance60
--jwt-jwks-uri <URL>JWKS endpoint URL for federated JWT authNone
--jwt-fallback-key <FILE>Fallback key file when JWKS is unavailableNone
--jwt-jwks-refresh <SECS>JWKS refresh interval3600
--jwt-role-claim <PATH>Claim path for extracting roles (e.g., roles, realm_access.roles)None
--jwt-role-map <MAP>Role mapping claim_value:mqtt_role, can be specified multiple timesNone
--jwt-default-roles <ROLES>Default roles for authenticated JWT users (comma-separated)None
--jwt-role-merge-mode <MODE>Role merge mode: merge or replace (deprecated, use --jwt-auth-mode)merge
--jwt-auth-mode <MODE>Federated auth mode: identity-only, claim-binding, trusted-rolesNone
--jwt-trusted-role-claim <PATH>Trusted role claim paths, can be specified multiple timesNone
--jwt-session-scoped-rolesWhether JWT roles are session-scoped (cleared on disconnect)None
--jwt-issuer-prefix <PREFIX>Custom issuer prefix for user ID namespacingNone
--jwt-config-file <FILE>Federated JWT config file (JSON) for multi-issuer setupNone
Broker OpenTelemetry Flags (requires opentelemetry feature)
FlagDescriptionDefault
--otel-endpoint <URL>OpenTelemetry OTLP endpoint (e.g., http://localhost:4317)None
--otel-service-name <NAME>OpenTelemetry service namemqttv5-broker
--otel-sampling <0.0-1.0>OpenTelemetry sampling ratio1.0

Broker Examples

Basic broker:

mqttv5 broker

Broker with TLS:

mqttv5 broker \
  --tls-cert server.pem \
  --tls-key server-key.pem \
  --tls-host 0.0.0.0:8883

Broker with authentication:

mqttv5 broker \
  --auth-password-file passwords.txt \
  --allow-anonymous=false

Broker with authentication and authorization (ACL):

mqttv5 broker \
  --auth-password-file passwords.txt \
  --acl-file acl.txt \
  --allow-anonymous=false

Broker with SCRAM-SHA-256 authentication:

mqttv5 broker \
  --auth-method scram \
  --scram-file scram_credentials.txt \
  --allow-anonymous=false

Broker with JWT authentication:

mqttv5 broker \
  --auth-method jwt \
  --jwt-algorithm rs256 \
  --jwt-key-file public_key.pem \
  --jwt-issuer "https://auth.example.com" \
  --jwt-audience "mqtt-broker"

Broker with federated JWT authentication:

mqttv5 broker \
  --auth-method jwt-federated \
  --jwt-jwks-uri "https://accounts.google.com/.well-known/jwks" \
  --jwt-fallback-key fallback_key.pem \
  --jwt-issuer "https://accounts.google.com" \
  --jwt-auth-mode claim-binding \
  --jwt-role-claim "roles" \
  --jwt-role-map "admin:admin" \
  --jwt-role-map "viewer:readonly"

Broker from config file:

mqttv5 broker --config broker-config.json

Multiple transports:

mqttv5 broker \
  --host 0.0.0.0:1883 \
  --tls-host 0.0.0.0:8883 \
  --tls-cert server.pem \
  --tls-key server-key.pem \
  --ws-host 0.0.0.0:8080

Broker with QUIC transport:

mqttv5 broker \
  --host 0.0.0.0:1883 \
  --quic-host 0.0.0.0:14567 \
  --tls-cert server.pem \
  --tls-key server-key.pem

Broker with adjusted $SYS statistics publishing:

# Publish $SYS topics every 30 seconds instead of the default 10
mqttv5 broker --allow-anonymous --sys-interval 30s

# Disable $SYS statistics entirely
mqttv5 broker --allow-anonymous --no-sys-topics

Broker with OpenTelemetry tracing:

mqttv5 broker \
  --otel-endpoint http://localhost:4317 \
  --otel-service-name my-mqtt-broker \
  --otel-sampling 1.0

Generate example configuration file:

mqttv5 broker generate-config --output config.json --format json

Broker as load balancer (redirects clients to backend brokers):

mqttv5 broker --config lb-config.json

Where lb-config.json contains a load_balancer section:

{
  "bind_addresses": ["0.0.0.0:1883"],
  "load_balancer": {
    "backends": [
      "mqtt://backend1.example.com:1883",
      "mqtt://backend2.example.com:1883"
    ]
  }
}

Clients connecting to the load balancer receive a CONNACK with reason code UseAnotherServer (0x9C) and a Server Reference property pointing to one of the backends. The client library automatically follows the redirect (up to 3 hops).

The load balancer only redirects — it does not broker messages. You must run the backend brokers separately:

mqttv5 broker --host 0.0.0.0:1884 --allow-anonymous

mqttv5 broker --host 0.0.0.0:1885 --allow-anonymous

mqttv5 broker --config lb-config.json

Where lb-config.json points to the running backends:

{
  "bind_addresses": ["0.0.0.0:1883"],
  "load_balancer": {
    "backends": [
      "mqtt://127.0.0.1:1884",
      "mqtt://127.0.0.1:1885"
    ]
  }
}

Publish through a load balancer (automatic redirect):

mqttv5 pub -t test/topic -m "Hello" \
  --url mqtt://lb.example.com:1883 \
  --non-interactive

Subscribe through a load balancer (automatic redirect):

mqttv5 sub -t test/# \
  --url mqtt://lb.example.com:1883 \
  --non-interactive

mqttv5 pub

Publish an MQTT message to a broker. Supports all transport types (TCP, TLS, WebSocket, QUIC), authentication methods, will messages, scheduled and repeated publishing, and request/response patterns.

Pub Flags

FlagDescriptionDefault
--topic, -t <TOPIC>MQTT topic (required)None
--message, -m <MSG>Message payloadNone
--file, -f <FILE>Read message from fileNone
--stdinRead message from stdinfalse
--url, -U <URL>Broker URL (mqtt://, mqtts://, ws://, wss://, quic://)None
--host, -H <HOST>Broker hostnamelocalhost
--port, -p <PORT>Broker port1883
--qos, -q <0|1|2>QoS level0
--retain, -rRetain messagefalse
--message-expiry-interval <SECS>Message expiry interval in secondsNone
--topic-alias <N>Topic alias (1-65535)None
--response-topic <TOPIC>Response topic for request/response pattern (MQTT 5.0)None
--correlation-data <HEX>Correlation data for request/response pattern (hex-encoded)None
--wait-responseWait for response after publishing (requires --response-topic)false
--timeout <SECS>Timeout when waiting for response30
--response-count <N>Number of responses to wait for (0 = unlimited until timeout)1
--output-format <FMT>Output format for responses: raw, json, verboseraw
--username, -u <USER>Authentication usernameNone
--password, -P <PASS>Authentication passwordNone
--auth-method <METHOD>Authentication method: password, scram, jwtpassword
--jwt-token <TOKEN>JWT token for JWT authenticationNone
--client-id, -c <ID>Client IDAuto-generated
--no-clean-startResume existing sessionfalse
--session-expiry <SECS>Session expiry interval in seconds0
--keep-alive, -k <SECS>Keep-alive interval60
--protocol-version <VER>MQTT protocol version: 3.1.1, 311, 4, 5, 5.05
--will-topic <TOPIC>Will message topicNone
--will-message <MSG>Will message payloadNone
--will-qos <0|1|2>Will message QoS0
--will-retainWill message retain flagfalse
--will-delay <SECS>Will message delay in secondsNone
--cert <FILE>TLS client certificate (PEM)None
--key <FILE>TLS client private key (PEM)None
--ca-cert <FILE>TLS CA certificate (PEM)None
--insecureSkip TLS certificate verificationfalse
--auto-reconnectEnable automatic reconnectionfalse
--non-interactiveSkip interactive promptsfalse
--delay <SECS>Delay before publishingNone
--repeat <N>Repeat publishing N times (0 = infinite until Ctrl+C)None
--interval <MS>Interval between repeated publishes in ms (requires --repeat)1000
--at <TIME>Schedule publish at specific time (e.g., 14:30, 2025-01-15T14:30:00)None
--quic-stream-strategy <S>QUIC stream strategy: control-only, per-publish, per-topic, per-subscriptioncontrol-only
--quic-flow-headersEnable QUIC flow headers for state recoveryfalse
--quic-flow-expire <SECS>Flow header expiry interval in seconds300
--quic-max-streams <N>Maximum concurrent QUIC streamsNone
--quic-datagramsEnable QUIC datagrams for unreliable transportfalse
--quic-connect-timeout <SECS>QUIC connection timeout in seconds30
--quic-early-dataEnable QUIC 0-RTT early datafalse
Pub Codec Flags (requires codec feature)
FlagDescriptionDefault
--codec <CODEC>Compress payload using codec: gzip, deflateNone
--codec-level <0-9>Codec compression level (requires --codec)6
--codec-min-size <BYTES>Minimum payload size for compression (requires --codec)128
Pub OpenTelemetry Flags (requires opentelemetry feature)
FlagDescriptionDefault
--otel-endpoint <URL>OpenTelemetry OTLP endpointNone
--otel-service-name <NAME>OpenTelemetry service namemqttv5-pub
--otel-sampling <0.0-1.0>OpenTelemetry sampling ratio1.0

Pub Examples

Basic publish:

mqttv5 pub -t test/topic -m "Hello, MQTT"

Publish with QoS 1:

mqttv5 pub -t sensors/temp -m "22.5" -q 1

Retained message:

mqttv5 pub -t status/online -m "true" -r

Publish to TLS broker:

mqttv5 pub -t test/topic -m "Secure message" \
  --url mqtts://broker.example.com:8883 \
  --ca-cert ca.pem

Publish over QUIC:

mqttv5 pub -t test/topic -m "QUIC message" \
  --url quic://broker.example.com:14567 \
  --ca-cert ca.pem

Publish over QUIC with multistream:

mqttv5 pub -t sensors/data -m '{"temp":25.5}' \
  --url quic://broker.example.com:14567 \
  --ca-cert ca.pem \
  --quic-stream-strategy per-publish \
  --quic-flow-headers \
  -q 1

Publish from file:

mqttv5 pub -t data/payload -f message.json -q 1

With will message:

mqttv5 pub -t test/topic -m "Online" \
  --will-topic test/status \
  --will-message "Offline" \
  --will-retain

With message expiry (60 seconds):

mqttv5 pub -t alerts/fire -m "Building A" --message-expiry-interval 60

With topic alias:

mqttv5 pub -t sensors/room1/temperature -m "22.5" --topic-alias 1

Request/response pattern:

mqttv5 pub -t commands/request -m '{"action":"status"}' \
  --response-topic commands/response \
  --wait-response \
  --timeout 10 \
  -q 1

Repeated publishing:

mqttv5 pub -t sensors/data -m "reading" --repeat 100 --interval 500

Scheduled publish:

mqttv5 pub -t alerts/scheduled -m "wake up" --at 14:30

SCRAM authentication:

mqttv5 pub -t test/topic -m "authenticated" \
  --auth-method scram \
  --username alice \
  --password secret

JWT authentication:

mqttv5 pub -t test/topic -m "jwt message" \
  --auth-method jwt \
  --jwt-token eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...

With codec compression:

mqttv5 pub -t data/large -f large_payload.json \
  --codec gzip --codec-level 9

Publish with OpenTelemetry tracing:

mqttv5 pub -t test/topic -m "Traced message" \
  --otel-endpoint http://localhost:4317 \
  --otel-service-name my-publisher

Using MQTT 3.1.1 protocol:

mqttv5 pub -t test/topic -m "v3.1.1 message" --protocol-version 3.1.1

mqttv5 sub

Subscribe to one or more MQTT topics and print received messages. The subscriber runs until interrupted (Ctrl+C) or a target message count is reached. Use --auto-reconnect for long-running subscribers that should survive broker restarts.

Sub Flags

FlagDescriptionDefault
--topic, -t <TOPIC>MQTT topic pattern (required)None
--url, -U <URL>Broker URL (mqtt://, mqtts://, ws://, wss://, quic://)None
--host, -H <HOST>Broker hostnamelocalhost
--port, -p <PORT>Broker port1883
--qos, -q <0|1|2>Subscription QoS level0
--verbose, -vInclude topic names in outputfalse
--show-properties, -sPrint MQTT v5 message properties (QoS, retain, expiry, content type, response topic, user properties, subscription IDs)false
--count, -n <N>Exit after receiving N messages0 (infinite)
--no-localDon't receive own published messagesfalse
--retain-handling <0|1|2>Retain handling: 0=send, 1=send if new, 2=don't send0
--retain-as-publishedKeep original retain flag on deliveryfalse
--subscription-identifier <ID>Subscription identifier (1-268435455)None
--username, -u <USER>Authentication usernameNone
--password, -P <PASS>Authentication passwordNone
--auth-method <METHOD>Authentication method: password, scram, jwtpassword
--jwt-token <TOKEN>JWT token for JWT authenticationNone
--client-id, -c <ID>Client IDAuto-generated
--no-clean-startResume existing sessionfalse
--session-expiry <SECS>Session expiry interval in seconds0
--keep-alive, -k <SECS>Keep-alive interval60
--protocol-version <VER>MQTT protocol version: 3.1.1, 311, 4, 5, 5.05
--will-topic <TOPIC>Will message topicNone
--will-message <MSG>Will message payloadNone
--will-qos <0|1|2>Will message QoS0
--will-retainWill message retain flagfalse
--will-delay <SECS>Will message delay in secondsNone
--cert <FILE>TLS client certificate (PEM)None
--key <FILE>TLS client private key (PEM)None
--ca-cert <FILE>TLS CA certificate (PEM)None
--insecureSkip TLS certificate verificationfalse
--auto-reconnectEnable automatic reconnectionfalse
--non-interactiveSkip interactive promptsfalse
--quic-stream-strategy <S>QUIC stream strategy: control-only, per-publish, per-topic, per-subscriptioncontrol-only
--quic-flow-headersEnable QUIC flow headers for state recoveryfalse
--quic-flow-expire <SECS>Flow header expiry interval in seconds300
--quic-max-streams <N>Maximum concurrent QUIC streamsNone
--quic-datagramsEnable QUIC datagrams for unreliable transportfalse
--quic-connect-timeout <SECS>QUIC connection timeout in seconds30
--quic-early-dataEnable QUIC 0-RTT early datafalse
Sub Codec Flags (requires codec feature)
FlagDescriptionDefault
--codec <CODEC>Enable codec decoding for incoming messages: gzip, deflate, allNone
Sub OpenTelemetry Flags (requires opentelemetry feature)
FlagDescriptionDefault
--otel-endpoint <URL>OpenTelemetry OTLP endpointNone
--otel-service-name <NAME>OpenTelemetry service namemqttv5-sub
--otel-sampling <0.0-1.0>OpenTelemetry sampling ratio1.0

Sub Examples

Basic subscribe:

mqttv5 sub -t test/topic

Subscribe with QoS 1:

mqttv5 sub -t important/data -q 1

Verbose output:

mqttv5 sub -t test/# -v

Show MQTT v5 message properties:

mqttv5 sub -t test/# --show-properties

No-local subscription:

mqttv5 sub -t test/topic --no-local

Subscribe over QUIC:

mqttv5 sub -t sensors/# \
  --url quic://broker.example.com:14567 \
  --ca-cert ca.pem \
  -v

Subscribe over QUIC with per-subscription streams:

mqttv5 sub -t sensors/# \
  --url quic://broker.example.com:14567 \
  --ca-cert ca.pem \
  --quic-stream-strategy per-subscription \
  --quic-flow-headers \
  -v

Subscription with identifier:

mqttv5 sub -t sensors/+/temperature --subscription-identifier 42 -v

With retain handling (don't send retained messages):

mqttv5 sub -t config/settings --retain-handling 2 -v

With retain-as-published (preserve retain flag):

mqttv5 sub -t status/# --retain-as-published -v

Persistent session:

mqttv5 sub -t data/# \
  --client-id my-subscriber \
  --no-clean-start \
  --session-expiry 3600 \
  -q 1

SCRAM authentication:

mqttv5 sub -t secure/# \
  --auth-method scram \
  --username alice \
  --password secret \
  -v

JWT authentication:

mqttv5 sub -t protected/# \
  --auth-method jwt \
  --jwt-token eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9... \
  -v

With codec decoding:

mqttv5 sub -t data/compressed -v --codec all

Subscribe with OpenTelemetry tracing:

mqttv5 sub -t test/# \
  --otel-endpoint http://localhost:4317 \
  --otel-service-name my-subscriber \
  -v

mqttv5 bench

Run performance benchmarks against a broker. Four modes are available: throughput (sustained message rate), latency (p50/p95/p99 round-trip times), connections (connection setup rate), and hol-blocking (head-of-line blocking measurement with per-topic trace output).

Bench Flags

FlagDescriptionDefault
--mode <MODE>Benchmark mode: throughput, latency, connections, hol-blockingthroughput
--duration <SECS>Test duration in seconds10
--warmup <SECS>Warmup period in seconds2
--payload-size <BYTES>Message payload size in bytes64
--topic, -t <TOPIC>Publish topicbench/test
--filter, -f <FILTER>Subscription filter (defaults to topic)Same as topic
--qos, -q <0|1|2>QoS level0
--url, -U <URL>Full broker URL (mqtt://, mqtts://, ws://, wss://, quic://)None
--host, -H <HOST>Broker hostnamelocalhost
--port, -p <PORT>Broker port1883
--client-id, -c <ID>Client ID prefixAuto-generated
--publishers <N>Number of publisher clients1
--subscribers <N>Number of subscriber clients1
--concurrency <N>Concurrent connections (connections mode)10
--topics <N>Number of topics (hol-blocking mode)4
--rate <N>Publish rate in msg/s (0 = unlimited)0
--payload-format <FMT>Payload format: raw, json, bebytes, compressed-jsonraw
--trace-dir <DIR>Directory for trace CSV output (hol-blocking mode)None
--insecureSkip TLS certificate verificationfalse
--ca-cert <FILE>TLS CA certificate (PEM)None
--cert <FILE>TLS client certificate (PEM)None
--key <FILE>TLS client private key (PEM)None
--pub-url <URL>Separate URL for publishers in HOL modeNone
--quic-stream-strategy <S>QUIC stream strategy: control-only, per-publish, per-topic, per-subscriptioncontrol-only
--quic-flow-headersEnable QUIC flow headers for state trackingfalse
--quic-flow-expire <SECS>Flow header expiry interval in seconds300
--quic-max-streams <N>Maximum concurrent QUIC streamsNone
--quic-datagramsEnable QUIC datagrams for unreliable transportfalse
--quic-connect-timeout <SECS>QUIC connection timeout in seconds30
--quic-early-dataEnable QUIC 0-RTT early datafalse

Bench Examples

Throughput benchmark (default):

mqttv5 bench --duration 15 --subscribers 5

Latency benchmark (measures p50/p95/p99):

mqttv5 bench --mode latency --duration 10

Connection rate benchmark:

mqttv5 bench --mode connections --duration 10 --concurrency 10

HOL blocking test:

mqttv5 bench --mode hol-blocking --topics 4 --rate 500 --duration 60 \
  --trace-dir ./traces

HOL blocking with separate publisher transport (TCP pub, QUIC sub):

mqttv5 bench --mode hol-blocking --topics 4 --rate 500 --duration 60 \
  --url quic://localhost:14567 --pub-url mqtt://localhost:1883 \
  --quic-stream-strategy per-topic --ca-cert ca.pem \
  --trace-dir ./traces

Custom payload and QoS:

mqttv5 bench --payload-size 1024 --qos 1 --publishers 5 --subscribers 5

Wildcard subscription testing:

mqttv5 bench --topic "bench/test" --filter "bench/+"

Benchmark over QUIC with per-topic streams:

mqttv5 bench --mode latency \
  --url quic://broker.example.com:14567 \
  --ca-cert ca.pem \
  --quic-stream-strategy per-topic

Benchmark with JSON payload format:

mqttv5 bench --payload-format json --payload-size 256

mqttv5 passwd

Manage the password file used by the broker's password authentication. Passwords are hashed with Argon2id before storage.

Passwd Usage

mqttv5 passwd [OPTIONS] <USERNAME> [FILE]

Passwd Flags

FlagDescription
--create, -cCreate new password file (overwrites if exists)
--batch, -b <P>Password on command line (insecure, use for scripts only)
--delete, -DDelete user from password file
--stdout, -nOutput hash to stdout instead of file

Passwd Examples

Create password file and add user:

mqttv5 passwd -c alice passwords.txt

Add user to existing file:

mqttv5 passwd bob passwords.txt

Delete user:

mqttv5 passwd -D alice passwords.txt

Batch mode (scripting):

mqttv5 passwd -b "mypassword" charlie passwords.txt

Generate hash to stdout:

mqttv5 passwd -n testuser

mqttv5 scram

Manage SCRAM-SHA-256 credentials for the broker's challenge-response authentication. SCRAM credentials use PBKDF2-HMAC-SHA256 key derivation with a configurable iteration count.

Scram Usage

mqttv5 scram [OPTIONS] <USERNAME> [FILE]

Scram Flags

FlagDescriptionDefault
--create, -cCreate new SCRAM file (overwrites if exists)false
--batch, -b <P>Password on command line (insecure, use for scripts only)None
--delete, -DDelete user from SCRAM filefalse
--stdout, -nOutput credentials to stdout instead of filefalse
--iterations, -i <N>PBKDF2 iteration count (minimum 10000)310000

Scram File Format

SCRAM credentials files use one line per user with five colon-separated fields:

username:salt:iterations:stored_key:server_key

Scram Examples

Create SCRAM file and add user:

mqttv5 scram -c alice scram_credentials.txt

Add user to existing file:

mqttv5 scram bob scram_credentials.txt

Delete user:

mqttv5 scram -D alice scram_credentials.txt

Batch mode (scripting):

mqttv5 scram -b "mypassword" charlie scram_credentials.txt

Generate credentials to stdout:

mqttv5 scram -n testuser

Custom iteration count:

mqttv5 scram -i 500000 alice scram_credentials.txt

mqttv5 acl

Manage ACL (Access Control List) files for the broker's topic-level authorization. ACL rules control which users can publish or subscribe to which topics, with support for wildcards, roles, and username substitution.

ACL Usage

mqttv5 acl <COMMAND>

ACL Commands

CommandDescription
add <user> <topic> <permission> --file FILEAdd ACL rule for a user
remove <user> [topic] --file FILERemove ACL rule(s) for user
list [user] --file FILEList ACL rules (all or for specific user)
check <user> <topic> <action> --file FILECheck if user can perform action on topic
role-add <role> <topic> <permission> --file FILEAdd ACL rule for a role
role-remove <role> [topic] --file FILERemove ACL rule(s) for a role
role-list [role] --file FILEList role definitions (all or specific role)
assign <user> <role> --file FILEAssign a role to a user
unassign <user> <role> --file FILERemove a role from a user
user-roles <user> --file FILEList roles assigned to a user

Permissions

  • read - Allow subscribe operations
  • write - Allow publish operations
  • readwrite - Allow both subscribe and publish
  • deny - Explicitly deny access

ACL Examples

Add rule allowing Alice to subscribe to sensors:

mqttv5 acl add alice "sensors/#" read --file acl.txt

Add rule allowing Bob to publish to actuators:

mqttv5 acl add bob "actuators/#" write --file acl.txt

Add rule for all users to access public topics:

mqttv5 acl add "*" "public/#" readwrite --file acl.txt

User-scoped rule with %u substitution (expands to authenticated username):

mqttv5 acl add "*" '$DB/u/%u/#' readwrite --file acl.txt

Deny access to admin topics:

mqttv5 acl add "*" "admin/#" deny --file acl.txt

List all ACL rules:

mqttv5 acl list --file acl.txt

List rules for specific user:

mqttv5 acl list alice --file acl.txt

Check if user can perform action:

mqttv5 acl check alice "sensors/temperature" read --file acl.txt

Remove specific rule:

mqttv5 acl remove alice "sensors/#" --file acl.txt

Remove all rules for user:

mqttv5 acl remove alice --file acl.txt

Add a role definition:

mqttv5 acl role-add sensor-reader "sensors/#" read --file acl.txt

Assign a role to a user:

mqttv5 acl assign alice sensor-reader --file acl.txt

List roles for a user:

mqttv5 acl user-roles alice --file acl.txt

Remove a role from a user:

mqttv5 acl unassign alice sensor-reader --file acl.txt

List all role definitions:

mqttv5 acl role-list --file acl.txt

Configuration File Reference

The broker accepts a JSON configuration file via --config. This section documents every field and provides ready-to-use examples.

Every field is optional. Any field omitted from the file falls back to the default listed in the tables below, including nested objects such as auth_config and storage_config, where individual sub-fields may also be omitted. A minimal config such as {} is valid and starts the broker entirely on defaults.

Complete Configuration Schema

{
  "bind_addresses": ["string"],
  "max_clients": number,
  "session_expiry_interval": duration,
  "max_packet_size": number,
  "topic_alias_maximum": number,
  "retain_available": boolean,
  "maximum_qos": 0 | 1 | 2,
  "wildcard_subscription_available": boolean,
  "subscription_identifier_available": boolean,
  "shared_subscription_available": boolean,
  "server_keep_alive": number | null,
  "response_information": string | null,
  "auth_config": AuthConfig,
  "tls_config": TlsConfig | null,
  "websocket_config": WebSocketConfig | null,
  "websocket_tls_config": WebSocketConfig | null,
  "storage_config": StorageConfig,
  "load_balancer": LoadBalancerConfig | null,
  "bridges": [BridgeConfig]
}

Core Broker Settings

FieldTypeDescriptionDefault
bind_addressesstring[]TCP listener addresses["0.0.0.0:1883", "[::]:1883"]
max_clientsnumberMaximum concurrent client connections10000
session_expiry_intervaldurationDefault session expiry for clients"1h"
max_packet_sizenumberMaximum MQTT packet size in bytes268435456 (256 MB)
topic_alias_maximumnumberMaximum number of topic aliases65535
retain_availablebooleanEnable retained messagestrue
maximum_qos0|1|2Maximum QoS level supported2
wildcard_subscription_availablebooleanEnable wildcard subscriptionstrue
subscription_identifier_availablebooleanEnable subscription identifierstrue
shared_subscription_availablebooleanEnable shared subscriptionstrue
server_keep_alivenumber|nullOverride client keep-alive (seconds)null
response_informationstring|nullResponse information propertynull

AuthConfig

{
  "allow_anonymous": boolean,
  "password_file": "string" | null,
  "acl_file": "string" | null,
  "auth_method": "None" | "Password" | "ScramSha256",
  "auth_data": string | null
}
FieldTypeDescriptionDefault
allow_anonymousbooleanAllow anonymous connectionstrue
password_filestring|nullPath to password filenull
acl_filestring|nullPath to ACL filenull
auth_methodstringAuthentication method"None"
auth_datastring|nullAdditional auth datanull

TlsConfig

{
  "cert_file": "string",
  "key_file": "string",
  "ca_file": "string" | null,
  "require_client_cert": boolean,
  "bind_addresses": ["string"]
}
FieldTypeDescriptionDefault
cert_filestringTLS certificate file (PEM)Required
key_filestringTLS private key file (PEM)Required
ca_filestring|nullCA certificate for client verificationnull
require_client_certbooleanRequire client certificates (mTLS)false
bind_addressesstring[]TLS listener addresses["0.0.0.0:8883", "[::]:8883"]

WebSocketConfig

{
  "bind_addresses": ["string"],
  "path": "string",
  "subprotocol": "string",
  "use_tls": boolean,
  "allowed_origins": ["string"] | null
}
FieldTypeDescriptionDefault
bind_addressesstring[]WebSocket listener addressesRequired
pathstringWebSocket endpoint path (non-matching paths return 404)"/mqtt"
subprotocolstringWebSocket subprotocol"mqtt"
use_tlsbooleanUse TLS for WebSocketfalse
allowed_originsstring[]|nullAllowed Origin headers for CSWSH prevention (null = all origins allowed)null

StorageConfig

{
  "backend": "File" | "Memory",
  "base_dir": "string",
  "cleanup_interval": duration,
  "enable_persistence": boolean
}
FieldTypeDescriptionDefault
backendstringStorage backend type"Memory"
base_dirstringBase directory for file storage"./mqtt_storage"
cleanup_intervaldurationCleanup interval for expired data"1h"
enable_persistencebooleanEnable message persistencefalse

LoadBalancerConfig

{
  "backends": ["string"]
}
FieldTypeDescriptionDefault
backendsstring[]Backend broker URLsRequired

When load_balancer is set, the broker acts as a connection redirector. On each CONNECT, it selects a backend using a hash of the client ID (byte-sum modulo backend count) and responds with CONNACK reason code UseAnotherServer (0x9C) containing a Server Reference property. The client automatically follows the redirect (up to 3 hops). The same client ID always routes to the same backend.

Backend URL format determines the transport the client uses after redirect:

SchemeTransportDefault Port
mqtt://host:portTCP1883
mqtts://host:portTLS8883
quic://host:portQUIC14567

The backend URL scheme must match the transport the client should use for the backend connection. The LB broker always requires at least one TCP bind_addresses entry, even for TLS-only or QUIC-only load balancing.

BridgeConfig

{
  "name": "string",
  "remote_address": "string",
  "client_id": "string",
  "username": "string" | null,
  "password": "string" | null,
  "use_tls": boolean,
  "tls_server_name": "string" | null,
  "ca_file": "string" | null,
  "client_cert_file": "string" | null,
  "client_key_file": "string" | null,
  "insecure": boolean | null,
  "alpn_protocols": ["string"] | null,
  "try_private": boolean,
  "clean_start": false,
  "keepalive": number,
  "protocol_version": "mqttv50",
  "reconnect_delay": duration,
  "initial_reconnect_delay": duration,
  "max_reconnect_delay": duration,
  "backoff_multiplier": number,
  "max_reconnect_attempts": number | null,
  "backup_brokers": ["string"],
  "topics": [TopicMapping]
}
FieldTypeDescriptionDefault
namestringUnique bridge nameRequired
remote_addressstringRemote broker address (host:port)Required
client_idstringClient ID for bridge connection"bridge-{name}"
usernamestring|nullAuthentication usernamenull
passwordstring|nullAuthentication passwordnull
use_tlsbooleanEnable TLS connectionfalse
tls_server_namestring|nullOverride TLS server name for verificationnull
ca_filestring|nullCA certificate file for TLS verificationnull
client_cert_filestring|nullClient certificate for mTLSnull
client_key_filestring|nullClient private key for mTLSnull
insecureboolean|nullDisable TLS certificate verificationfalse
alpn_protocolsstring[]|nullALPN protocols (e.g., ["x-amzn-mqtt-ca"] for AWS IoT)null
try_privatebooleanSend bridge user property (Mosquitto compatible)true
clean_startbooleanMust be false: the bridge acknowledges a remote message only after routing it locally, which needs a persistent sessionfalse
keepalivenumberKeep-alive interval in seconds60
protocol_versionstringMust be "mqttv50": bridge flow control uses MQTT 5.0 session expiry and receive maximum"mqttv50"
reconnect_delaydurationReconnection delay (deprecated)"5s"
initial_reconnect_delaydurationInitial reconnection delay"5s"
max_reconnect_delaydurationMaximum reconnection delay"5m"
backoff_multipliernumberExponential backoff multiplier2.0
max_reconnect_attemptsnumber|nullMax reconnection attempts (null = infinite)null
backup_brokersstring[]Backup broker addresses for failover[]
topicsTopicMapping[]Topic mappings for message forwardingRequired

TopicMapping

{
  "pattern": "string",
  "direction": "in" | "out" | "both",
  "qos": "AtMostOnce" | "AtLeastOnce" | "ExactlyOnce",
  "local_prefix": "string" | null,
  "remote_prefix": "string" | null
}
FieldTypeDescriptionDefault
patternstringTopic pattern with MQTT wildcardsRequired
directionstringMessage flow directionRequired
qosstringQoS level for forwardingRequired
local_prefixstring|nullPrefix to add to local topicsnull
remote_prefixstring|nullPrefix to add to remote topicsnull

Direction values: "in" forwards from remote to local, "out" forwards from local to remote, and "both" enables bidirectional forwarding.

Complete Configuration Examples

Minimal Configuration

{
  "bind_addresses": ["0.0.0.0:1883"]
}

Basic Authenticated Broker

{
  "bind_addresses": ["0.0.0.0:1883"],
  "auth_config": {
    "allow_anonymous": false,
    "password_file": "/etc/mqtt/passwords.txt",
    "auth_method": "Password"
  }
}

TLS Broker

{
  "bind_addresses": ["0.0.0.0:1883"],
  "tls_config": {
    "cert_file": "/etc/mqtt/certs/server.pem",
    "key_file": "/etc/mqtt/certs/server-key.pem",
    "bind_addresses": ["0.0.0.0:8883"]
  }
}

Load Balancer Broker

{
  "bind_addresses": ["0.0.0.0:1883"],
  "load_balancer": {
    "backends": [
      "mqtt://backend1.example.com:1883",
      "mqtt://backend2.example.com:1883",
      "mqtt://backend3.example.com:1883"
    ]
  }
}

TLS Load Balancer Broker

{
  "bind_addresses": ["0.0.0.0:1883"],
  "tls_config": {
    "cert_file": "/etc/mqtt/certs/server.pem",
    "key_file": "/etc/mqtt/certs/server-key.pem",
    "bind_addresses": ["0.0.0.0:8883"]
  },
  "load_balancer": {
    "backends": [
      "mqtts://backend1.example.com:8883",
      "mqtts://backend2.example.com:8883"
    ]
  }
}

QUIC Load Balancer Broker

{
  "bind_addresses": ["0.0.0.0:1883"],
  "quic_config": {
    "cert_file": "/etc/mqtt/certs/server.pem",
    "key_file": "/etc/mqtt/certs/server-key.pem",
    "bind_addresses": ["0.0.0.0:14567"]
  },
  "load_balancer": {
    "backends": [
      "quic://backend1.example.com:14567",
      "quic://backend2.example.com:14567"
    ]
  }
}

Broker with Bridge

{
  "bind_addresses": ["0.0.0.0:1883"],
  "bridges": [
    {
      "name": "cloud-bridge",
      "remote_address": "broker.cloud.example.com:8883",
      "client_id": "edge-bridge-01",
      "use_tls": true,
      "ca_file": "/etc/mqtt/certs/ca.pem",
      "topics": [
        {
          "pattern": "sensors/#",
          "direction": "out",
          "qos": "AtLeastOnce"
        },
        {
          "pattern": "commands/#",
          "direction": "in",
          "qos": "AtLeastOnce"
        }
      ]
    }
  ]
}
{
  "bind_addresses": ["0.0.0.0:1883", "[::]:1883"],
  "max_clients": 5000,
  "session_expiry_interval": "2h",
  "max_packet_size": 134217728,
  "retain_available": true,
  "maximum_qos": 2,
  "wildcard_subscription_available": true,
  "subscription_identifier_available": true,
  "shared_subscription_available": true,
  "auth_config": {
    "allow_anonymous": false,
    "password_file": "/etc/mqtt/passwords.txt",
    "auth_method": "Password"
  },
  "tls_config": {
    "cert_file": "/etc/mqtt/certs/server.pem",
    "key_file": "/etc/mqtt/certs/server-key.pem",
    "ca_file": "/etc/mqtt/certs/ca.pem",
    "require_client_cert": true,
    "bind_addresses": ["0.0.0.0:8883", "[::]:8883"]
  },
  "websocket_config": {
    "bind_addresses": ["0.0.0.0:8080"],
    "path": "/mqtt",
    "subprotocol": "mqtt"
  },
  "storage_config": {
    "backend": "File",
    "base_dir": "/var/lib/mqtt",
    "cleanup_interval": "30m",
    "enable_persistence": true
  },
  "bridges": [
    {
      "name": "aws-iot-bridge",
      "remote_address": "your-endpoint.iot.us-east-1.amazonaws.com:8883",
      "client_id": "my-device",
      "use_tls": true,
      "ca_file": "/etc/mqtt/certs/AmazonRootCA1.pem",
      "client_cert_file": "/etc/mqtt/certs/device-cert.pem",
      "client_key_file": "/etc/mqtt/certs/device-key.pem",
      "alpn_protocols": ["x-amzn-mqtt-ca"],
      "initial_reconnect_delay": "5s",
      "max_reconnect_delay": "5m",
      "backoff_multiplier": 2.0,
      "topics": [
        {
          "pattern": "device/data/#",
          "direction": "out",
          "qos": "AtLeastOnce"
        }
      ]
    }
  ]
}

Special Topics

This section covers file formats, certificate requirements, and bridge behavior that apply across multiple commands.

Duration Format

Configuration uses humantime format for duration values:

  • "5s" - 5 seconds
  • "30m" - 30 minutes
  • "1h" - 1 hour
  • "2h30m" - 2 hours 30 minutes
  • "1d" - 1 day

Password File Format

Password files use one line per user:

username:$argon2id$v=19$m=...
  • Username followed by colon
  • Argon2 hash of password
  • Use mqttv5 passwd command to manage

SCRAM Credentials File Format

SCRAM files use one line per user with five colon-separated fields:

username:salt:iterations:stored_key:server_key
  • Use mqttv5 scram command to manage

ACL File Format

ACL files define topic-level access control with one rule per line:

user <username> topic <pattern> permission <type>

Format:

  • <username> - Username or * for wildcard (all users)
  • <pattern> - Topic pattern with MQTT wildcards (+ for single level, # for multi-level). Use %u to substitute the authenticated username.
  • <type> - Permission: read, write, readwrite, or deny

Role-based ACL rules:

role <rolename> topic <pattern> permission <type>
assign <username> <rolename>

Example ACL file:

user alice topic sensors/# permission read
user bob topic actuators/# permission write
user admin topic admin/# permission readwrite
user * topic public/# permission readwrite
user * topic admin/# permission deny
user * topic $DB/u/%u/# permission readwrite
role sensor-reader topic sensors/# permission read
role actuator-writer topic actuators/# permission write
assign alice sensor-reader
assign bob actuator-writer

Rule Priority:

  • More specific rules override general rules
  • User-specific rules take precedence over wildcard rules
  • Deny rules have highest priority

Security:

  • %u substitution rejects usernames containing +, #, or / to prevent wildcard injection
  • Anonymous clients never match %u patterns
  • Sessions are bound to authenticated user identity -- reconnecting with a different user is rejected
  • On session restore, subscriptions are re-checked against current ACL rules

Use mqttv5 acl command to manage ACL files.

TLS Certificates

Requirements:

  • PEM format for all certificates and keys
  • Certificate chain in single file (server cert first, intermediates after)
  • Private key must be unencrypted
  • CA file can contain multiple CA certificates

Bridge Configuration

Direction Types:

  • in - Receive messages from remote broker
  • out - Send messages to remote broker
  • both - Bidirectional message forwarding

Reconnection Behavior:

  • Exponential backoff: delay = initial_delay * (multiplier ^ attempt)
  • Default: 5s -> 10s -> 20s -> 40s -> ... -> 300s (max)
  • Resets to initial delay after successful connection

Backup Brokers:

  • Tried in order when primary fails
  • Each uses same TLS and auth configuration
  • Failover is automatic

Topic Prefixes:

  • local_prefix - Added to topics on local broker
  • remote_prefix - Added to topics on remote broker
  • Applied before/after forwarding based on direction