MQTT Gateway
bext acts as an MQTT 5 gateway broker — IoT devices connect via standard MQTT, and messages route into bext's plugin system and pub/sub infrastructure. bext is not a full-persistence broker; it bridges MQTT traffic into your application logic.
Enabling MQTT
Add a [mqtt] section to bext.config.toml:
[mqtt]
enabled = true
bind = "0.0.0.0:1883"
tls_bind = "0.0.0.0:8883"
max_connections = 10000
max_packet_size_bytes = 65536
Compile with the mqtt feature flag:
bext build --features mqtt
Listener Ports
MQTT runs on its own TCP listeners, separate from the HTTP port:
| Port | Protocol | Description |
|---|---|---|
| 1883 | MQTT | Plain TCP (LAN / dev use). |
| 8883 | MQTTS | TLS-encrypted (production). |
TLS uses the same certificate configured in the site's [tls] section.
Gateway Model
bext is a gateway, not a standalone broker. This means:
- Incoming MQTT publishes are forwarded to bext plugins and the internal pub/sub bus.
- Plugins can subscribe to MQTT topics and react to messages.
- There is no built-in disk-backed message persistence. Messages that cannot be delivered are dropped after QoS retries.
IoT Device ──mqtt──▶ bext ──▶ Plugin handler
│
└──▶ PubSub bus (SSE, WebSocket subscribers)
MQTT 5 Features
bext implements the MQTT 5.0 protocol (RFC 9431):
Quality of Service
| QoS Level | Guarantee | Use Case |
|---|---|---|
| 0 | At most once (fire and forget) | Sensor telemetry. |
| 1 | At least once (ack required) | Commands, alerts. |
| 2 | Exactly once (4-step handshake) | Billing, state changes. |
Sessions
- Clean Start — client starts fresh, no stored state.
- Persistent Session — bext stores subscriptions and pending QoS 1/2 messages for the session expiry interval.
[mqtt]
session_expiry_secs = 3600 # 1 hour default
Topic Wildcards
Standard MQTT wildcard subscriptions are supported:
| Wildcard | Example | Matches |
|---|---|---|
+ |
sensors/+/temp |
sensors/room1/temp, etc. |
# |
sensors/# |
Everything under sensors/. |
Authentication
MQTT clients authenticate via the token-in-username pattern. The client sends a bearer token as the MQTT username, and bext validates it through the same Auth capability used for HTTP:
Username: Bearer eyJhbGciOi...
Password: (empty or ignored)
Alternatively, use client certificate authentication over MQTTS for device fleets where token management is impractical.
[mqtt.auth]
mode = "token" # "token" | "cert" | "none"
HTTP Publish Bridge
Publish MQTT messages from any HTTP client via the built-in bridge endpoint:
POST /__bext/mqtt/publish
Content-Type: application/json
{
"topic": "sensors/room1/temp",
"payload": "22.5",
"qos": 1,
"retain": false
}
This is useful for backend services that do not have an MQTT client library, or for triggering device commands from a web dashboard.
Plugin Integration
Plugins can subscribe to MQTT topics and publish messages:
use bext::mqtt::{MqttBus, MqttMessage};
async fn on_mqtt_message(msg: MqttMessage, bus: &MqttBus) {
println!("topic={} payload={}", msg.topic, msg.payload_str());
// Publish a response
bus.publish("devices/ack", b"ok", QoS::AtLeastOnce).await?;
}
Register the subscription in the plugin manifest:
[plugin]
name = "sensor-handler"
[[plugin.mqtt_subscriptions]]
topic = "sensors/+/temp"
qos = 1
Retained Messages
When retain = true, bext stores the last message per topic in memory.
New subscribers immediately receive the retained message for matching
topics. This is standard MQTT behavior for "last known value" patterns.
Will Messages
Clients can set a Last Will and Testament (LWT) on connect. If the client disconnects ungracefully, bext publishes the will message to the specified topic:
Will Topic: devices/sensor-42/status
Will Payload: offline
Will QoS: 1
Will Retain: true
Metrics
| Metric | Description |
|---|---|
mqtt_connections_active |
Current MQTT client connections. |
mqtt_messages_received_total |
Messages received from clients. |
mqtt_messages_sent_total |
Messages sent to clients. |
mqtt_subscriptions_active |
Active topic subscriptions. |
Feature Flag
MQTT requires the mqtt feature flag:
bext build --features mqtt
Without this flag, the [mqtt] config section is ignored.
bext is a gateway, not a persistence broker. Messages that cannot be delivered within QoS retry limits are dropped — there is no durable queue behind them. For workloads that require guaranteed delivery across broker restarts, bridge to an external broker (Mosquitto, EMQX, etc.) from a plugin rather than relying on bext's in-memory session store.
Port 1883 (plain TCP) is suitable for LAN or dev use only. In production,
use port 8883 (MQTTS) and the cert auth mode so device credentials
are not transmitted in plaintext.
Related
- Plugins overview — how to register MQTT subscription handlers in a plugin
- Server-Sent Events — HTTP push alternative for browser consumers of the same pub/sub bus
- WebSockets — bidirectional HTTP alternative for web clients that cannot use native MQTT
- Auth capability — token and certificate auth wired into the MQTT listener
- Capabilities overview — full list of bext runtime capabilities
Links
- mqtt.org — official MQTT project site
- OASIS MQTT Version 5.0 specification — the MQTT 5 standard bext implements