MQTT brokers in 2026: revisit Eclipse Mosquitto, EMQX and NanoMQ before you connect another device to a broker
Most teams do not choose an MQTT broker. They inherit one. Somebody installed Mosquitto from the distribution package on a small VM years ago, gave every device the same username, and it has been quietly running since. Then the device count grows, a customer asks for an audit trail, or the VM reboots during patching and an alarm is missed. That is when the team starts reading about clusters, edge brokers and licences, and finds that a lot has changed in two years.
This post compares the three brokers that Indian teams most often look at for self-hosting in 2026: Eclipse Mosquitto, EMQX and NanoMQ. We also look briefly at VerneMQ and HiveMQ Community Edition. We cover versions, licences (including the EMQX move to the Business Source License), clustering, persistence, access control, bridging, TLS, footprint, upgrades and security history, and when not to add a broker at all.
Several earlier posts sit close to this one. RabbitMQ, NATS and Kafka queues is about brokers between services; MQTT is about devices. Kafka and Redpanda often sits behind the broker for replay. Time-series databases in 2026 covers where readings land. Schema registries in 2026 matters because device payloads drift too. TLS certificate automation in 2026 covers the per-device certificates we recommend below, mesh VPNs in 2026 is one way to keep a broker off the public internet, and reverse proxies in 2026 matters for MQTT over WebSockets and the PROXY protocol. Finally, workflow automation in 2026 covers Node-RED, which is often the first thing people connect to a broker.
We end with a small drill: NanoMQ 0.25.7 on loopback with authentication and ACLs, tested with a Python MQTT 5 client. We say clearly what we did not run.
A scenario to keep us honest
Imagine a company near Hosur that grows export roses and other cut flowers in polyhouses, stores them in cold rooms, and moves them in refrigerated trucks to the cargo terminal at Kempegowda International Airport in Bengaluru for flights to Europe and West Asia. The company is invented for this post. It has three farm sites around Hosur and Krishnagiri, a packhouse with 12 cold rooms, about 20 reefer trucks, and an engineering team of eight people, two of whom look after infrastructure.
The setup today:
- About 900 sensors and controllers: temperature and humidity in polyhouses, fogger and shade-net controllers, cold-room temperature probes, door sensors, and 4G telematics boxes in the trucks.
- Farm gateways read Modbus sensors and publish to MQTT; cold rooms and trucks publish directly.
- One Mosquitto 2.0 broker from the distribution package on a VM in a cloud region in Mumbai. Port 1883 is open to the internet without TLS, because the truck boxes “could not do certificates” when they were bought.
- One password file. Most devices share two or three usernames. There is no ACL file.
- A Node-RED instance subscribes to
#, writes to a time-series database and sends alerts.
Four things push the team to revisit the broker. First, during a kernel patch the VM took longer than usual to come back, Node-RED did not reconnect cleanly, and a cold-room door left open was noticed only by a person on the night shift. Second, a European importer asked for cold-chain records from packhouse to aircraft, and for an explanation of who can publish temperature readings. The honest answer was “any device”. Third, the company plans two more farm sites and a second packhouse, which would roughly double the device count. Fourth, three engineers have proposals: one wants an EMQX cluster on Kubernetes, one wants NanoMQ on every farm gateway, and one says “just upgrade Mosquitto and fix the configuration”.
We will come back to Hosur in the worked plan.
The short version
- Eclipse Mosquitto is the small, stable, single-node broker most people already know. It is dual licensed EPL-2.0 or EDL-1.0 (BSD-3-Clause). The current release is 2.1.2 (9 February 2026), after the 2.1.0 feature release in January. Open-source Mosquitto has no clustering, and bridges do not share sessions.
- EMQX is a large, feature-rich, clustered broker written in Erlang. From 5.9.0 (May 2025) the open-source and enterprise editions are one product under the Business Source License 1.1. Independent single nodes are free in production, a cluster needs a commercial licence, and hosted or embedded use for third parties is not covered. The current LTS is 6.3.2 (17 October 2026 IST).
- NanoMQ is an MIT-licensed edge broker in C, part of LF Edge, built on the NNG library. It is small, has strong bridging with an SQLite cache for offline periods, and has no clustering. The current release is 0.25.7 (21 October 2026 IST). Its shipped defaults are permissive, and it had 21 GitHub security advisories when we checked, mostly 2026 memory-safety bugs.
- VerneMQ (Apache-2.0, Erlang, clustered) and HiveMQ Community Edition (Apache-2.0, Java, single node) are real options.
- Choose by deployment shape first: a broker at the edge, a single central broker, or a cluster. Then check the licence for that shape. Then put the real limits in per-device credentials, ACLs and TLS, because several 2026 CVEs around Mosquitto were shipped configuration, not broker code.
Where things stand on 30 October 2026
Eclipse Mosquitto. The project publishes its releases on mosquitto.org and tags on GitHub, not GitHub releases. Version 2.1.0 came on 29 January 2026 and was the first feature release since 2.0 in December 2020. Version 2.1.1 followed on 4 February and 2.1.2 on 9 February 2026; both are bugfix releases. The 2.0 line ended with 2.0.22 on 11 July 2025. Version 2.0.21 on 6 March 2025 was a security release, including a further fix for CVE-2023-28366. We found no newer Mosquitto release as of 30 October 2026.
EMQX. The GitHub releases are all titled “EMQX Enterprise” now. The 6.3 line is the current LTS: 6.3.0 on 3 September 2026 at 9:49 PM IST, 6.3.1 on 18 September and 6.3.2 on 17 October 2026 at 12:48 AM IST. Older lines still get patches, such as 6.1.5 and 6.0.4 on 29 September and 5.10.5 on 17 September 2026. The last Apache-2.0 release was v5.8.9 on 31 December 2025. The README says there will be no 6.4; the next version is 7.0, which the security policy describes as alpha and not for production. The EMQX lifecycle page gives LTS lines three years of support: 5.8 until 27 August 2027 and 6.3 until 2 September 2029. Feature releases get 18 months, so 5.9 reaches end of life on 1 November 2026, two days after this post, and 5.10 on 8 December 2026. The old 4.4 LTS ends in December 2026.
NanoMQ. The latest GitHub release is 0.25.7, published on 21 October 2026 at 3:41 PM IST. Its notes call it the “first beta release of 0.25.7”, although GitHub does not mark it as a pre-release, so read it as a beta. It adds Zephyr RTOS support, a per-bridge cache, PKCS#11 for TLS keys, an option to use the peer certificate as the username, a REST call to kick a client, and fixes for a SCRAM bounds check and a use-after-free in the rule engine. The last plain bugfix release was 0.25.6 on 19 August 2026, and 0.25.3 on 13 July 2026 was the first official 0.25 release.
VerneMQ and HiveMQ CE. VerneMQ 2.2.1 came on 17 September 2026 with a fix for stale shared subscriptions, after 2.2.0 on 9 August 2026. HiveMQ CE 2026.5 came on 28 May 2026, after 2025.5 in November 2025.
The first question: which shape do you actually need?
Before comparing features, write down where the broker sits. There are three common shapes, and most mistakes come from choosing a broker built for one shape and using it for another.
Shape 1: a broker at the edge
A small broker runs on a gateway at a farm, a factory line or inside a vehicle. Local devices talk to it over the LAN. It keeps working when the internet link drops, and it forwards selected topics upstream when the link is back. What matters: small footprint, good bridging, a disk buffer and safe defaults, because nobody will log in to that gateway for months.
Shape 2: a single central broker
One broker in a data centre or cloud region. All devices and backend consumers connect to it. What matters: simple configuration, good ACLs and TLS, fast restart and persistence. For many businesses with a few thousand devices this is enough, if the edge can tolerate a few minutes of downtime.
Shape 3: a cluster
Several broker nodes that share sessions, subscriptions and routes, so a node can fail or be upgraded while clients reconnect to another node and continue. What matters: real session sharing, rolling upgrades, low latency between nodes, and the cost of running and licensing it.
A quick test
Ask the business a direct question: “If the central broker is down for ten minutes at 3 AM, what is lost?” If the answer is “nothing, because the gateways buffer and the trucks retry”, you probably need shape 1 plus shape 2, not shape 3. If the answer is “a payment terminal fails” or “a safety interlock does not get its command”, then you need shape 3, and you should budget for it.
What each broker is
Eclipse Mosquitto
Mosquitto was written by Roger Light and is an Eclipse Foundation project; its GitHub repository dates from 2016, but the broker is older than that. It is a single C process with a small footprint that runs on anything from a Raspberry Pi to a large VM. It supports MQTT 5.0, 3.1.1 and 3.1. It has TCP, TLS and WebSocket listeners, bridges, an authentication plugin interface, and a dynamic security plugin for users, groups and roles.
The 2.1.0 release in January 2026 is the biggest change in five years, and several items matter for operators:
acl_file,password_fileandper_listener_settingsare deprecated in favour of the new acl-file and password-file plugins and listener-specific options. The release notes say the old options will be removed in 3.0. They still work in 2.1, but plan the move now.- The default
max_packet_sizeis now 2,000,000 bytes. Before 2.1 it was effectively 256 MB. Most telemetry is far smaller, but if you send firmware images or camera frames over MQTT, check before you upgrade. - New plugins: persist-sqlite for persistence, and sparkplug-aware for Sparkplug B setups. The man page now recommends plugin-based persistence over the built-in
mosquitto.dbfile. - WebSockets are built in, and PROXY protocol v1 and v2 is supported, which matters behind HAProxy.
- TLS 1.1 support for clients was removed. The default minimum for listeners is TLS 1.2 with TLS 1.3 allowed.
- The project says idle wakeups are reduced by up to 100 times. That is the project’s own claim about idle behaviour, not a throughput benchmark.
Version 2.1.2 refuses to start if you set persistence true and also load a persistence plugin, which is a sensible guard against two writers.
The defaults are safer than many people remember. Since 2.0, allow_anonymous is false by default. If you define no listener at all, Mosquitto listens only for local connections and allows anonymous clients there. That is why the classic mistake is not “Mosquitto is open by default”, but “we added listener 1883 and allow_anonymous true to make the device work, and never removed them”.
A minimal central configuration for 2.1 with TLS and per-device certificates looks like this. We still use the classic acl_file here because it is easy to read and works in 2.1, but treat it as a bridge to the acl-file plugin:
# /etc/mosquitto/mosquitto.conf (sketch for 2.1.x; not run in our drill)
per_listener_settings false
allow_anonymous false
# devices: TLS with client certificates, CN becomes the username
listener 8883 0.0.0.0
cafile /etc/mosquitto/ca/devices-ca.pem
certfile /etc/mosquitto/tls/broker.pem
keyfile /etc/mosquitto/tls/broker.key
tls_version tlsv1.2
require_certificate true
use_identity_as_username true
# backend consumers on the private network only
listener 8884 10.20.0.5
cafile /etc/mosquitto/ca/backend-ca.pem
certfile /etc/mosquitto/tls/broker.pem
keyfile /etc/mosquitto/tls/broker.key
require_certificate true
use_identity_as_username true
acl_file /etc/mosquitto/acl
max_queued_messages 1000
max_packet_size 262144
And an ACL that gives each device only its own topics, using the %u pattern for the username taken from the certificate:
# /etc/mosquitto/acl
# every device: publish own telemetry, read own commands
pattern write farm/+/%u/telemetry
pattern read farm/+/%u/cmd
# ingest service: read all telemetry, write commands
user ingest
topic read farm/+/+/telemetry
topic write farm/+/+/cmd
Mosquitto’s ACL file denies anything not listed. Test your ACL with a client that should be refused, not only with one that should work.
EMQX
EMQX is an Erlang broker whose repository dates from December 2012. EMQ, the company behind it, says it launched EMQX under Apache 2.0 in 2013, and its licence FAQ says the company was founded in 2017. It is a different class of product from Mosquitto. A single EMQX node gives you MQTT 5.0, 3.1.1 and 3.1, MQTT over QUIC, gateways for MQTT-SN, CoAP and LwM2M, a dashboard on port 18083, a SQL-like rule engine, more than 50 data integrations, many authentication backends and a large REST API.
EMQX 6.0 (September 2025) added Message Queues with $q/ topics, Namespaces for multi-tenancy, and durable sessions stored in RocksDB. EMQX 6.3 (September 2026, LTS) focuses on security defaults and footprint:
- Strict MQTT packet parsing is on by default. The OpenAPI specification and Prometheus endpoints now need authentication. Credential hashing is stronger.
- An optional hardened security profile, switched on with
EMQX_SECURITY_PROFILE=hardened. EMQ says it plans to make this the default in 7.0. - Feature Gates let you start EMQX with a smaller set of features. EMQ says
EMQX_FEATURES=ESSENTIALbrings idle boot memory under 100 MB. That is the vendor’s own figure. - QoS 0 flow control, Topic Metrics v2 and an MQTT Agent plugin.
Clustering in EMQX 5 and later uses Mria on top of Erlang’s distribution, with two node roles: core nodes hold the replicated database, and replicant nodes serve clients and copy data from the cores. The documentation asks for network latency under 10 ms between nodes and says the cluster becomes unavailable above 100 ms. Discovery can be manual, static, DNS, etcd or Kubernetes. Autoheal is on by default.
The default dashboard login is admin with password public, and the dashboard forces a password change on first login. Keep port 18083 off the internet anyway.
An EMQX file-based ACL uses Erlang terms. The same per-device rule from above looks like this:
%% etc/acl.conf (EMQX file authorizer, sketch)
{allow, {username, "ingest"}, subscribe, ["farm/+/+/telemetry"]}.
{allow, {username, "ingest"}, publish, ["farm/+/+/cmd"]}.
{allow, all, publish, ["farm/+/${username}/telemetry"]}.
{allow, all, subscribe, ["farm/+/${username}/cmd"]}.
{deny, all}.
Check the placeholder syntax against the authorisation page for your exact version before you use it; EMQX has changed it across major versions.
NanoMQ
NanoMQ is an MQTT broker for the edge, written in C on top of NNG (nanomsg next generation), with an actor-style design that uses all CPU cores. It is an LF Edge project and is MIT licensed. Its documentation says it was first released in January 2021. It supports MQTT 5.0 and 3.1.1; the README lists enhanced authentication and server redirection as the MQTT 5 features it does not support.
What NanoMQ does well is the edge job:
- Bridges upstream over MQTT on TCP, TLS or QUIC, with a hybrid mode that falls back from QUIC to TCP, topic remapping, and a transparent mode.
- An SQLite cache for bridged messages, so readings are kept on disk while the uplink is down and sent later. 0.25.7 adds a per-bridge cache.
- A rule engine, WebHooks, an HTTP API and protocol gateways.
- Small size. The documentation says the boot footprint can be under 200 KB with the minimum feature set, and that NanoMQ is “up to 10 times faster than Mosquitto on a multi-core CPU”. Both are the project’s own claims, and the test report linked from the README is for a very old version (0.2.5). The 0.25.7 binary we downloaded was 2.28 MB and linked only to libc and libm.
There is no clustering. If you need more than one NanoMQ, you bridge them.
The shipped default configuration is permissive, and you must change it before a device ever connects. In the 0.25.7 package, the default nanomq.conf listens on 0.0.0.0:1883 and WebSockets on 0.0.0.0:8083, runs the HTTP API on port 8081 with username admin and password public, sets allow_anonymous = true and no_match = allow, ships a plaintext password file with admin and client both set to public, and ends the sample ACL with {"permit": "allow"}. It is a convenience default, and exactly the pattern that becomes a CVE when a gateway maker ships it unchanged.
A bridge from a farm gateway to the central broker, in the shape of the shipped example configuration, looks like this:
# nanomq.conf on a farm gateway (sketch based on the 0.25.7 example config; not run)
listeners.tcp { bind = "192.168.10.1:1883" }
http_server { ip_addr = "127.0.0.1", port = 8081, username = gwadmin, password = "from-your-secret-store" }
auth {
allow_anonymous = false
no_match = deny
deny_action = disconnect
password = { include "/etc/nanomq/nanomq_pwd.conf" }
acl = { include "/etc/nanomq/nanomq_acl.conf" }
}
sqlite { disk_cache_size = 102400 }
bridges.mqtt.central {
server = "tls+mqtt-tcp://mqtt.example.internal:8883"
proto_ver = 5
clientid = "gw-hosur-farm2"
clean_start = false
keepalive = 60s
backoff_max = 60s
ssl {
keyfile = "/etc/nanomq/tls/gw-hosur-farm2.key"
certfile = "/etc/nanomq/tls/gw-hosur-farm2.pem"
cacertfile = "/etc/nanomq/tls/central-ca.pem"
}
forwards = [
{ local_topic = "farm/hosur-farm2/+/telemetry", remote_topic = "farm/hosur-farm2/+/telemetry", qos = 1 }
]
}
Two details from our drill are worth knowing here. The http_server block has its own ip_addr, which defaults to 0.0.0.0; setting only a port is not enough to keep the API on loopback. And NanoMQ’s password file is plaintext, so protect the file and the gateway.
VerneMQ and HiveMQ CE, briefly
VerneMQ is an Apache-2.0 Erlang broker with built-in clustering; its GitHub repository dates from 2015. It is the one fully open-source clustered option among the brokers in this post. Development is slower than EMQX, the community is smaller, and the company behind it sells support and binary packages. If you need a cluster and cannot accept the EMQX licence, VerneMQ deserves a proper trial, with your own failure tests.
HiveMQ Community Edition is the Apache-2.0 single-node version of the commercial HiveMQ broker. It runs on Java 11 or later, supports MQTT 3.x and 5 fully, and has an extension system for authentication and integrations. Clustering is only in the commercial editions. It suits teams who already run Java services and want a clean MQTT 5 implementation on one node.
We did not run VerneMQ or HiveMQ CE for this post.
Side by side
Licence, editions and governance
- Mosquitto: EPL-2.0 or EDL-1.0 (a BSD-3-Clause style licence), at your choice. Eclipse Foundation governance. No licence change in its history. Cedalo, a commercial vendor, sells Pro Mosquitto with clustering, a management centre and more; the open-source broker stays as it is.
- EMQX: Business Source License 1.1 for 5.9.0 and later. The Additional Use Grant allows production use of a single node, as long as you do not offer it to third parties on a hosted or embedded basis. Educational and non-profit users may use it in production without that limit if it is not for commercial profit. Each version changes to Apache-2.0 four years after its publication. EMQ’s licence FAQ adds three points that matter: any number of independent single nodes is free, a cluster needs a commercial licence, and embedding EMQX in a gateway you sell counts as embedded use. Versions released under Apache-2.0, up to v5.8.9, stay Apache-2.0. The enterprise edition had already moved to BSL in April 2023; the 2025 change unified the two. Contributions need a CLA.
- NanoMQ: MIT. LF Edge project.
- VerneMQ: Apache-2.0. HiveMQ CE: Apache-2.0, with clustering only in the commercial HiveMQ editions.
The EMQX change deserves a calm reading. For a company that runs one EMQX node for its own devices, nothing practical changes. For a company that wants an EMQX cluster, the licence now decides the cost of high availability, and that cost should go into the plan from day one. For a company that sells a product with EMQX inside (a gateway, an appliance, a hosted IoT platform for clients), the BSL grant does not cover you, and you need either a commercial agreement or a different broker. The Apache-2.0 v5.8.9 build still works but gets no further open-source releases.
MQTT 5 support
All five brokers support MQTT 5.0 and 3.1.1. Mosquitto 2.1 added broker-created topic aliases and accept_protocol_versions per listener. EMQX also adds MQTT over QUIC, which is EMQ’s own extension, not part of the OASIS standard. NanoMQ lacks enhanced authentication and server redirection. In practice, check the three MQTT 5 features your devices actually use: session expiry, message expiry (a cold-room reading from yesterday should not arrive as if it were current) and shared subscriptions ($share/group/topic), which let several backend consumers split the load.
Clustering and high availability
- Mosquitto: no clustering in the open-source broker. You can run two independent brokers with bridges between them, but bridges forward messages only. Sessions, subscriptions and in-flight QoS 1 and 2 messages are not shared, so a client that moves to the other broker starts fresh. Cedalo’s commercial Pro Mosquitto offers HA clusters of at least three nodes, according to its own pages. The practical open-source approach is a single node with fast restart, persistence on a reliable disk, and clients that reconnect with backoff.
- EMQX: real clustering with Mria, core and replicant nodes, shared sessions and routes, and rolling upgrades between adjacent minor versions. Under BSL 5.9 and later, more than one node needs a licence. Keep nodes in one region with low latency; the documentation’s 10 ms guidance rules out stretching a cluster between Mumbai and Hyderabad.
- NanoMQ: no clustering. Scale by bridging, not by clustering.
- VerneMQ: open-source clustering. Test network splits and node loss yourself before trusting it with critical traffic.
- HiveMQ CE: no clustering.
Persistence and sessions
- Mosquitto: with
persistence true, the built-in store writesmosquitto.dbeveryautosave_intervalseconds (1800 by default) and on shutdown. A crash between saves loses whatever changed since the last save. The 2.1 man page recommends plugin-based persistence, such as the new persist-sqlite plugin, instead. Do not set both; 2.1.2 refuses to start if you do.max_queued_messagesdefaults to 1000 per client, which is the number of messages kept for an offline persistent client before older ones are dropped. - EMQX: sessions in memory by default, with durable sessions on RocksDB since 6.0. The README warns that durable session state does not survive the move from 5 to 6, so plan that upgrade with clients that can resubscribe.
- NanoMQ: session state in memory, and the SQLite cache for bridged messages. The cache is the feature that matters for an edge broker.
Whichever broker you choose, a QoS 1 or 2 message is only as safe as the weakest point on its path. A device resends an unacknowledged QoS 1 message only if it keeps its own session state, and many cheap devices do not.
Authentication and ACLs
- Mosquitto: password file (hashed, and 2.1 uses 64-byte salts), the new password-file and acl-file plugins, the dynamic security plugin for users, groups and roles managed at runtime, client certificates with
use_identity_as_username, and an external plugin interface. ACL patterns support%uand%cfor username and client ID. - EMQX: built-in database, file, LDAP, external databases such as PostgreSQL and Redis, HTTP and JWT, plus client certificates, with placeholders for username and client ID in rules.
- NanoMQ: plaintext password file and a JSON-style ACL file, HTTP authentication, and from 0.25.7 the peer certificate as username.
no_matchdecides what happens when no ACL rule matches, anddeny_actiondecides whether a denied client is just ignored or disconnected. Defaults are allow; change them.
The single most useful rule is the same for all of them: one credential per device, and an ACL that limits each device to its own topics. Shared usernames make it impossible to revoke one device or to tell an auditor who published a reading.
Bridging
Mosquitto has mature bridges with topic remapping and TLS, and holds messages for the bridge within its normal queue limits while the remote is down. EMQX offers MQTT bridges as one of its many data integrations. NanoMQ has the strongest edge bridging of the group: TCP, TLS and QUIC with fallback, topic remapping, and an SQLite cache on disk while offline.
TLS
All of them support TLS listeners and mutual TLS. Some details:
- Mosquitto’s
tls_versionsets the minimum version; the default allows TLS 1.2 and 1.3. 2.1 removed TLS 1.1 for clients and added--tls-keylogfor debugging. - EMQX’s October 2026 advisory GHSA-qxwr-jcff-c3wm is a reminder that outbound TLS from the broker also matters: after two public root certificates were compromised and intermediates revoked on 18 and 19 October 2026, EMQX images still trusted those roots, and EMQX does not check CRL or OCSP on outgoing connector TLS by default. EMQ re-published the 6.3.2 image on 22 October with a cleaned operating system bundle, but the Python certifi bundle was unchanged. The advisory names 6.3.3 as the patched version, and when we checked on 30 October 2026 no 6.3.3 tag existed on GitHub. If your EMQX connects out to cloud services, pin the CA you need instead of trusting a full public bundle.
- NanoMQ 0.25.7 adds PKCS#11, so keys can live in a secure element on gateways that have one.
For devices that “cannot do certificates”, check the current firmware first. If they truly cannot, put them on a private APN or a VPN and treat the link as the security boundary.
Footprint
We do not quote performance numbers we did not measure. Mosquitto is a single small C process that is happy on a Raspberry Pi. EMQX is a large Erlang system; EMQ says the ESSENTIAL feature set brings idle memory under 100 MB in 6.3, and a full node needs more, so plan a real VM or container. NanoMQ is small: in our drill the idle broker used about 4.6 MB of resident memory, from one run on one box, not a benchmark. HiveMQ CE needs memory for the JVM. For load, test with your own message size, topic count and QoS; vendor benchmarks are the vendor’s own runs on the vendor’s chosen setup.
Security history
Read this section for patterns, not for a score.
- Mosquitto has a modest CVE history at NVD. Recent broker issues include CVE-2023-28366 (memory leak with QoS 2 messages, fixed in 2.0.16 and further in 2.0.21), CVE-2023-5632 (EPOLLOUT handling, versions up to 2.0.5), CVE-2024-8376 (up to 2.0.18a) and CVE-2024-3935 (bridge, 2.0.0 to 2.0.18). CVE-2024-10525 (9.8) was in the libmosquitto client library’s SUBACK handling, versions 1.3.2 to 2.0.18, which matters if your devices use libmosquitto. Older issues such as CVE-2018-12550 (empty ACL file) and CVE-2018-20145 (ACL bypass with
per_listener_settings) are the reason we test refusals. The more striking pattern in 2026 is in products that embed Mosquitto: CVE-2026-73669 describes a smart-home bridge whose embedded broker listened on all interfaces without authentication, CVE-2026-71960 a router with a hard-coded JWT secret in its Mosquitto auth plugin, and CVE-2026-77056 and CVE-2026-77060 a home automation controller with the same default broker credentials on every unit and a world-readable password file. None of these is a bug in Mosquitto’s code. All of them are configuration shipped to customers. - EMQX had two GitHub security advisories, both medium. GHSA-cp9x-5qwc-fj6r (CVE-2026-44725, 6.6, June 2026): stale plugin allowlist entries and no payload digest meant a compromised administrator or API key could reach remote code execution through plugins; fixed in 5.8.11, 5.9.3, 5.10.4, 6.0.3, 6.1.2 and 6.2.1. The second is the trust-store issue above. The security policy says fixes are not automatically backported to every supported line, and the 5.x and 6.x lines do not share fixes, so read each advisory for your line.
- NanoMQ had 21 GitHub security advisories when we checked: 4 high, 12 medium and 5 low, most of them published in 2026 and most of them memory-safety bugs in packet parsing, such as an out-of-bounds read in variable byte integer decoding (CVE-2026-21888), a heap overflow in subscription decoding (CVE-2026-73863), a use-after-free (CVE-2025-59946), memory leaks (CVE-2026-73979) and a quadratic-time denial of service (CVE-2026-44639). A long list can partly reflect active security review, but a NanoMQ gateway on an untrusted network needs regular upgrades.
- VerneMQ and HiveMQ CE had no GitHub security advisories. That does not mean they have no bugs.
Operations and upgrades
- Mosquitto: one binary and one config file. Run
mosquitto --test-config(new in 2.1) before a restart, watch the$SYStopics or an exporter, and remember that an upgrade is a restart, so persistent sessions and restart time matter. - EMQX: dashboard, REST API, Prometheus metrics and a CLI. Rolling upgrades work only between adjacent minor versions, and the README lists specific paths, such as 5.8.7 or later going to 5.9.1 or 5.10.1 first. Prefer the 6.3 LTS line and track the 18-month end of life of feature lines.
- NanoMQ: one binary, a HOCON config, an HTTP API and log files. At the edge the hard part is remote rollout and rollback across gateways.
A worked plan for Hosur
Here is how the Hosur team could go from one open broker to something they can explain to an importer.
- Answer the downtime question. The business agrees that ten minutes without the central broker is acceptable if nothing is lost and cold-room alarms still fire locally. Truck telemetry can arrive late. That rules out the need for a cluster today.
- Design the topic tree.
farm/<site>/<device>/telemetry,farm/<site>/<device>/cmdandfarm/<site>/<device>/status, with the device ID equal to the certificate CN. Trucks usefleet/<truck>/.... Write it down and review it like an API. - Give every device its own identity. Issue client certificates from a small internal CA (the TLS automation post covers step-ca). Devices that cannot do TLS move to the private APN the telecom provider already offers, and get their own username and password.
- Put a broker at each farm. A NanoMQ 0.25.x on each farm gateway, listening only on the farm LAN, with anonymous access off,
no_match = deny, a local ACL, the HTTP API on loopback, and a TLS bridge to the centre with the SQLite cache on. Local alarm logic (cold-room door open for more than five minutes) runs at the farm, so it works when the uplink is down. Mosquitto would also work here, but it has no dedicated on-disk cache for bridged messages like NanoMQ’s. - Run a single central broker. The team compares Mosquitto 2.1.2 and a single EMQX 6.3 node, which is allowed under the BSL grant because it is for the company’s own devices and not hosted for others. They choose Mosquitto 2.1.2: the configuration fits in one review, the team knows it, and they do not need EMQX’s rule engine. EMQX stays the first option if they later need a paid cluster.
- Close the internet port. Port 1883 is closed. Devices on the internet use 8883 with mutual TLS. Backend services connect on a private listener.
- Replace the
#subscriber. Node-RED gets its own identity with read access tofarm/+/+/statusonly. A small ingest service with a shared subscription writes telemetry to the time-series database and, for the cold chain, to a Kafka topic that keeps a replayable record for the importer. - Make restarts boring. Switch from
mosquitto.dbto the persist-sqlite plugin, keep the data directory on a reliable disk, and test a restart under load: how long until 900 clients are back? - Measure, then decide on a cluster. Track reconnect time, queue depth and dropped messages. When the second packhouse comes up, or if a customer contract demands near-zero downtime, revisit an EMQX cluster with a commercial licence or a VerneMQ trial, with real failure tests.
- Read advisories every week. Subscribe to Mosquitto releases, NanoMQ advisories and, if EMQX is added later, EMQX advisories for the exact line in use. Upgrade gateways one farm at a time.
When each is better
- Mosquitto is better when you want one small, well-understood broker per site or one central node, your team values a short readable configuration, and a restart of a minute or so is acceptable.
- EMQX is better when you need clustering with shared sessions, a large number of connections, many built-in integrations, multi-tenancy or MQTT over QUIC, and you will pay for the cluster or a single node is enough.
- NanoMQ is better at the edge, on a gateway or in a vehicle, where you need strong bridging and disk buffering, and someone will keep it upgraded.
- VerneMQ is better when you need an open-source cluster and can invest in testing it yourself.
- HiveMQ CE is better for a Java team that wants a clean single-node MQTT 5 broker with an extension model.
When not to adopt an MQTT broker
- Your “devices” are backend services. Service-to-service traffic usually wants a queue or a log with consumer groups and replay. MQTT shines with many small, unreliable clients.
- You have a dozen devices on one LAN with one consumer. A small HTTP endpoint or a collector may be simpler.
- Your vendor already runs a managed IoT platform you pay for. Do not add a self-hosted broker in front of it unless there is a clear reason, such as offline buffering at a site.
- You need request and response with strict ordering and transactions. MQTT 5 has response topics, but it is not a database or an RPC framework.
- Nobody owns it. A broker on the internet with nobody reading its advisories is how many of the 2026 CVEs above were born.
A short history
MQTT was created in 1999 by Andy Stanford-Clark and Arlen Nipper for monitoring oil pipelines over expensive satellite links, which explains its small headers and its focus on unreliable networks. Version 3.1.1 became an OASIS standard in 2014, and MQTT 5.0 followed in 2019 with reason codes, session and message expiry, shared subscriptions, user properties and topic aliases. EMQX grew from 2012 into a large clustered broker, and NanoMQ appeared in 2021 for the edge. The big change of the last two years is licensing: EMQX’s move to BSL in 2025 means one of the best-known MQTT brokers is now source available, with free single nodes and paid clusters.
Decision guide
Start with the shape
- Edge gateway with an unreliable uplink: NanoMQ, or Mosquitto with a bridge if the offline periods are short.
- One central broker, a few thousand devices, minutes of downtime acceptable: Mosquitto 2.1, or a single EMQX 6.3 node if you want its integrations and dashboard.
- Cluster needed: EMQX with a commercial licence, or VerneMQ if you need open source and can test it yourself, or a commercial HiveMQ or Pro Mosquitto.
Then check the licence for your use
- Own devices, own servers, single node: all five are fine.
- Cluster: EMQX needs a licence; Mosquitto and HiveMQ CE do not cluster; VerneMQ does under Apache-2.0.
- You sell a product or a hosted service with the broker inside: EMQX BSL does not cover it without an agreement. Mosquitto, NanoMQ, VerneMQ and HiveMQ CE are permissive or weak copyleft; read the EPL-2.0 or EDL terms for Mosquitto with your legal team.
Checklist
- Every device has its own credential, preferably a client certificate.
- Anonymous access is off on every listener, including edge gateways.
- ACLs limit each device to its own topics. Unmatched requests are denied.
- A test proves a device cannot publish to another device’s topic or subscribe to
#. - No plaintext MQTT port is open to the internet.
- Admin APIs and dashboards (EMQX 18083, NanoMQ HTTP API, Mosquitto dynamic security control topics) are on private networks with non-default passwords.
- TLS minimum is 1.2. Outbound TLS from the broker trusts only the CAs it needs.
- Persistence is set up the recommended way for your version, on a reliable disk.
max_queued_messages(or the equivalent) andmax_packet_sizeare set deliberately.- Restart time under real load is measured.
- Licence is checked for your deployment shape, including any plan to sell or host.
- Version pinned and advisories followed for your exact line.
- An upgrade and rollback plan exists for edge gateways.
Common mistakes
- One username for all devices. You cannot revoke one device and you cannot answer an auditor.
allow_anonymous trueleft from a test. In Mosquitto 2.x this is almost always a line somebody added.- Trusting the shipped defaults of an edge broker. NanoMQ’s defaults are allow-all. Set
allow_anonymous,no_match, the ACL and the HTTP API address yourself. - Setting only a port and assuming loopback. In our drill, NanoMQ’s HTTP API bound to
0.0.0.0because we set the port and notip_addr. Check withss -ltnpafter every start. - Using bridges as if they were a cluster. Bridged Mosquitto brokers do not share sessions; clients that fail over lose their state.
- Building on EMQX clustering without reading the licence. It is free in the trial and paid after.
- Ignoring the 2.1 Mosquitto changes. A firmware upload over MQTT larger than 2 MB will fail after the upgrade unless you set
max_packet_size. - Using QoS 2 everywhere. It costs round trips and broker state. Use QoS 1 with idempotent consumers for most telemetry.
The drill we ran
The drill was small and local, and ran on 30 October 2026 between about 2:20 AM and 2:30 AM IST, entirely on loopback under a user folder. We did not install packages system-wide, start system services or touch system directories.
- We downloaded the NanoMQ 0.25.7 Linux amd64 package from its GitHub release and checked its SHA-256 against the published checksum. We unpacked it into a local folder without installing it.
- We read the shipped
nanomq.confand confirmed the permissive defaults described above. - We wrote our own config: MQTT on
127.0.0.1:18830, anonymous off,no_match = deny,deny_action = disconnect, two users (coldroom-07andingest) and an ACL that letscoldroom-07publish only its own telemetry andingestreadfarm/hosur/+/telemetry, with a final deny. - On the first start we had set only the HTTP port. NanoMQ logged that the REST server was on
0.0.0.0:18081, andssconfirmed it. We stopped the broker within about a minute without running any test against it, addedip_addr = "127.0.0.1", and restarted. After that, both listeners were on 127.0.0.1 only. - With paho-mqtt 2.1.0 in a Python virtual environment, using MQTT 5:
- An anonymous connection was refused. So was a wrong password. In both cases the client saw a disconnect with “Unspecified error” rather than a clear “not authorised” reason code, which is worth knowing when you debug device logs.
ingestsubscribed tofarm/hosur/+/telemetryand was granted QoS 1.coldroom-07published a QoS 1 reading with a 60-second message expiry, andingestreceived it.coldroom-07then published tofarm/hosur/coldroom-09/telemetry. It was not delivered; the broker logged an ACL deny and disconnected the device.- A second
ingestsession subscribed to#. It got no SUBACK and was disconnected after an ACL deny; the first session was unaffected.
- The idle broker used about 4.6 MB of resident memory after the tests. One run on one box; not a benchmark.
- We stopped the broker and confirmed with pgrep that no NanoMQ or Mosquitto process was left.
What we did not run: Eclipse Mosquitto (we downloaded the 2.1.2 source, but the box had no build tools, so it was not built), EMQX, VerneMQ and HiveMQ CE. We did not test TLS, bridging, the SQLite cache, persistence, clustering, upgrades or load. A useful next step is a TLS bridge from NanoMQ to a local Mosquitto, with the uplink cut for five minutes.
Unlearn, re-learn
- Unlearn “the broker is just a pipe”. Re-learn that the broker is where device identity and permissions are enforced, and that an open broker lets anyone publish your sensor readings.
- Unlearn “open source means free to cluster”. Re-learn to check the licence for your deployment shape; for EMQX 5.9 and later, a cluster is a commercial product.
- Unlearn “more nodes means more reliable”. Re-learn that a single node with fast restart and buffering at the edge is often more reliable than a cluster the team does not understand.
- Unlearn “defaults are safe”. Re-learn to read the shipped config, set every listener address and auth option yourself, and check open ports after each start.
- Unlearn “we tested that the device can connect”. Re-learn to test what the device must not be able to do.
Sources
- Eclipse Mosquitto: Mosquitto repository, LICENSE, 2.1.2 released, 2.1.1 released, 2.1.0 released, 2.0.21 released, mosquitto.conf man page, CVE-2023-28366 at NVD, CVE-2024-10525 at NVD, CVE-2024-3935 at NVD, CVE-2026-73669 at NVD, CVE-2026-77056 at NVD, Pro Mosquitto by Cedalo
- EMQX: EMQX repository, LICENSE (BSL 1.1), 6.3.2 release, v5.8.9 release, EMQX adopts the Business Source License, Licence FAQ, EMQX 6.3 announcement, Version 6 release notes, Lifecycle and EOL dates, Clustering, Authorisation, Security policy, GHSA-cp9x-5qwc-fj6r, GHSA-qxwr-jcff-c3wm
- NanoMQ: NanoMQ repository, LICENSE (MIT), 0.25.7 release, 0.25.3 release, Documentation, MQTT over TCP bridge, Access control, Security advisories, CVE-2026-21888 at NVD, CVE-2026-73863 at NVD
- VerneMQ and HiveMQ CE: VerneMQ repository, VerneMQ 2.2.1 release, VerneMQ LICENSE, HiveMQ CE repository, HiveMQ CE 2026.5 release, HiveMQ CE LICENSE
- MQTT and tools: MQTT 5.0 specification (OASIS), mqtt.org, Eclipse Paho Python client
- Related posts on Revisit.Tech: RabbitMQ, NATS and Kafka queues, Kafka and Redpanda, time-series databases in 2026, schema registries in 2026, TLS certificate automation in 2026, mesh VPNs in 2026, reverse proxies in 2026, workflow automation in 2026
Releted Posts
Web application firewalls in 2026: revisit ModSecurity, OWASP Coraza and BunkerWeb before you put another WAF in front of your app
A web application firewall is one of those things that gets added after a bad week. A penetration test report arrives, or a customer sends a security questionnaire with a line that says “Do you use a WAF?
Read moreReverse proxies in 2026: revisit NGINX, Caddy and HAProxy before you put another proxy in front of your app
Almost every web application we run has something sitting in front of it. A few virtual machines run the actual code, and one or two small servers in front of them accept HTTPS, keep certificates, spread traffic, hide a dead backend and write the access log.
Read moreDNS servers in 2026: revisit CoreDNS, PowerDNS and BIND 9 before you add another DNS record by hand
In most companies, somebody still adds internal DNS records by hand. A new database gets an IP address, an engineer logs in to the DNS server, types one line into a zone file or a web console, and saves.
Read more