MQTT Swiftlet
Overview
The MQTT Swiftlet provides MQTT 3.1.1 protocol support for SwiftMQ routers, allowing MQTT clients to connect, publish, and subscribe to topics using the standard MQTT protocol. It manages MQTT connections, sessions (including persistent sessions), topic subscriptions, retained messages, and integrates with SwiftMQ's topic and queue infrastructure for message delivery and storage.
Features
MQTT Protocol Support
The MQTT Swiftlet implements the MQTT 3.1.1 protocol, handling all standard MQTT message types (CONNECT, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, PINGREQ, PINGRESP, DISCONNECT). It manages client authentication, session establishment, keepalive, and protocol-level error handling. The Swiftlet supports both clean and persistent sessions, with session state and subscriptions stored for reconnecting clients.
Session Persistence
Persistent MQTT sessions are stored in the SwiftMQ router and survive client disconnects and router restarts. Session state, including topic subscriptions and pending QoS 1/2 messages, is maintained in the internal session store queue (sys$mqtt_sessionstore). Sessions are automatically removed after a configurable timeout if unused.
Will Message Handling
The Swiftlet supports MQTT 'Last Will and Testament' messages. If a client disconnects unexpectedly and has set a Will, the Will message is published to the specified topic with the configured QoS and retain flag.
Retained Messages
The Swiftlet maintains a memory-based retainer for MQTT retained messages. When a message is published with the retain flag, it is stored and delivered to new subscribers matching the topic. Retained messages are removed when a zero-length payload is published to the topic.
Configuration Example:
<swiftlet name="sys$mqtt">
<declarations>
<connection-templates>
<connection-template name="default" max-message-size="2097152"/>
</connection-templates>
</declarations>
<listeners>
<listener name="mqtt1" port="1884" max-connections="100" connection-template="default"/>
</listeners>
</swiftlet>
Listener and Connection Management
The MQTT Swiftlet allows the configuration of one or more TCP listeners, each accepting MQTT client connections on a specified port and (optionally) bind address. Each listener can limit the maximum number of concurrent connections and apply a host access list to restrict incoming connections by IP or hostname. Listeners use connection templates to define socket and buffer parameters, message size limits, and TCP options.
Host Access List
Each listener can be configured with a host access list, specifying allowed client hosts using predicates. Only clients matching an entry in the list are permitted to connect.
Connection Templates
Connection templates define network and protocol parameters for connections, such as buffer sizes, idle timeouts, maximum message size, and socket factory class. These templates can be reused across multiple listeners.
Configuration Example:
<swiftlet name="sys$mqtt">
<listeners>
<listener name="mqtt2" port="1885" max-connections="50" connection-template="default">
<host-access-list>
<host-access-entry name="192.168.1.%"/>
<host-access-entry name="10.0.0.%"/>
</host-access-list>
</listener>
</listeners>
</swiftlet>
Topic Subscription and Message Routing
MQTT topic subscriptions are mapped to SwiftMQ topics, with MQTT wildcards (#, +) translated to SwiftMQ's % wildcard. Subscriptions are managed per session, and messages are routed using SwiftMQ's topic infrastructure. Temporary and durable consumers are used for non-persistent and persistent subscriptions, respectively. Retained messages are delivered to new subscribers as required by the MQTT specification.
Topic Name Translation
MQTT topic names use / as a separator, which are translated to . for SwiftMQ topics. Wildcards are validated and translated: # and + are mapped to % in SwiftMQ. Wildcards are not allowed at the root or in invalid positions.
Subscription Management
Subscriptions are tracked per session. For persistent sessions, subscriptions are stored and restored on reconnect. Subscriptions are removed when the client unsubscribes or the session expires.
Usage and Statistics Collection
The Swiftlet provides detailed usage statistics for MQTT connections, sessions, and topic subscriptions. It tracks messages sent and received per connection and subscription, both as instantaneous rates (messages/sec) and cumulative totals. Statistics collection is performed at a configurable interval and is visible in the management interface.
Configurable Collection Interval
The collect-interval property controls how often message rate statistics are updated (in milliseconds).
Configuration Example:
<swiftlet name="sys$mqtt" collect-interval="5000"/>
Session Timeout and Cleanup
Persistent MQTT sessions that are not associated with a connection are automatically removed after a configurable timeout period. This helps prevent the accumulation of unused session state. The timeout is specified in hours via the session-timeout property.
Configuration Example:
<swiftlet name="sys$mqtt" session-timeout="24"/>
Internal Queue Naming
sys$mqtt_sessionstore— Internal queue for storing persistent MQTT session state (session store).tmp$<sequence>-<startuptime>— Temporary queues used for non-durable MQTT topic subscriptions.<clientId>$<durableName>— Durable subscription queue for persistent MQTT topic subscriptions.
Configuration Guide
Add a New MQTT Listener on a Custom Port with Host Restriction
Use this scenario to allow MQTT clients to connect only from a specific subnet, on a non-default port, with a limit on maximum concurrent connections.
- Define a new listener under the MQTT Swiftlet with the desired port and maximum connections.
- Add host access entries to restrict allowed client IPs.
- Optionally, reference a custom connection template if needed.
<swiftlet name="sys$mqtt">
<listeners>
<listener name="restricted" port="2883" max-connections="10" connection-template="default">
<host-access-list>
<host-access-entry name="172.16.0.%"/>
</host-access-list>
</listener>
</listeners>
</swiftlet>
Increase Maximum MQTT Message Size
Use this scenario if your MQTT clients need to send messages larger than the default maximum size (10MB).
- Edit the connection template used by your listeners.
- Set the
max-message-sizeattribute to the required value (in bytes).
<swiftlet name="sys$mqtt">
<declarations>
<connection-templates>
<connection-template name="default" max-message-size="20971520"/>
</connection-templates>
</declarations>
</swiftlet>
Reduce Session Timeout for Faster Cleanup
Shorten the period after which unused persistent MQTT sessions are deleted, to avoid resource buildup.
- Set the
session-timeoutattribute on the MQTT Swiftlet to the desired number of hours.
<swiftlet name="sys$mqtt" session-timeout="12"/>
Configuration Reference
The top-level entity in routerconfig.xml is <swiftlet name="sys$mqtt">.
<swiftlet name="sys$mqtt"> Properties
These properties are attributes of the <swiftlet name="sys$mqtt"> entity.
| Parameter | Type | Default | Mandatory | Reboot Required | Description |
|---|---|---|---|---|---|
collect-interval |
Long | 1000 |
No | No | Collect Interval Messages/Sec |
session-timeout |
Long | 168 |
No | No | Time in hours after which a unused Session is deleted |
<swiftlet name="sys$mqtt" collect-interval="1000" session-timeout="168"/>
<declarations> Entity
Declarations Section
This is a fixed child entity of <swiftlet name="sys$mqtt">.
<swiftlet name="sys$mqtt">
<declarations/>
</swiftlet>
<connection-templates> in <declarations>
Templates for Connections
Each <connection-template> entry is identified by its name attribute (the Connection Template).
| Parameter | Type | Default | Mandatory | Reboot Required | Description |
|---|---|---|---|---|---|
socketfactory-class |
String | com.swiftmq.net.PlainSocketFactory |
No | No | Socketfactory Class |
use-tcp-no-delay |
Boolean | true |
No | No | Use Tcp No Delay |
idle-timeout |
Long | 90000 |
No | No | Inactivity timeout (ms) after which a Connection is disconnected |
max-message-size |
Integer | 10485760 |
No | No | Maximum Message Size (range: 0–2147483647) |
reject-disconnect-delay |
Long | 5000 |
No | No | Time (ms) after which a rejected Connection is closed (min: 1000) |
router-input-buffer-size |
Integer | 131072 |
No | No | Router Network Input Buffer Size (min: 1024) |
router-input-extend-size |
Integer | 65536 |
No | No | Router Network Input Extend Size (min: 1024) |
router-output-buffer-size |
Integer | 131072 |
No | No | Router Network Output Buffer Size (min: 1024) |
router-output-extend-size |
Integer | 65536 |
No | No | Router Network Output Extend Size (min: 1024) |
<swiftlet name="sys$mqtt">
<declarations>
<connection-templates>
<connection-template name="..."/>
</connection-templates>
</declarations>
</swiftlet>
<listeners> in <swiftlet name="sys$mqtt">
Listener Definitions
Each <listener> entry is identified by its name attribute (the Listener).
| Parameter | Type | Default | Mandatory | Reboot Required | Description |
|---|---|---|---|---|---|
bindaddress |
String | — | No | No | Listener Bind IP Address |
port |
Integer | 1883 |
Yes | No | Listener Port |
max-connections |
Integer | -1 |
Yes | No | Maximum Connections for Listener |
connection-template |
String | default |
Yes | No | Connection Template to use |
<swiftlet name="sys$mqtt">
<listeners>
<listener name="..." port="..." max-connections="..." connection-template="..."/>
</listeners>
</swiftlet>
<host-access-list> in <listeners>
Host Access List
Each <host-access-entry> entry is identified by its name attribute (the Host Access Entry).
<swiftlet name="sys$mqtt">
<listeners>
<listener name="...">
<host-access-list>
<host-access-entry name="..."/>
</host-access-list>
</listener>
</listeners>
</swiftlet>
Changelog
13.2.0 (2025-11-03)
- SessionStore: migrated from XStream to JSON