MQTT.Agent - open protocol for AI agents

Retour au blog
Security TLS

The Security Defaults We Chose for MQTT

TLS-only listeners, deny-by-default ACLs, and per-org mountpoints. What we picked and why.

February 12, 2026
6 min de lecture
By CloudSignal Team

Why MQTT has a bad security reputation

MQTT did not earn its reputation from the protocol itself. It earned it from how the protocol was usually deployed. Three patterns showed up in tutorials, demos, and a surprising number of production stacks, and together they shaped how people think about MQTT security.

The first is plaintext port 1883 facing the public internet. A decade of tutorials open with “connect to broker.example.com on 1883” and never come back to TLS. The second is anonymous authentication. Every getting-started guide on every popular broker turns it on by default so a beginner can publish in two minutes, and a non-trivial number of those configs make it to staging and then to production. The third is a flat topic namespace. Every connected client can subscribe to # and read everything the broker has ever routed.

None of these are inherent to MQTT. They are deployment defaults that became cultural. When we started, we rejected all three. The rest of this post is what we picked instead and why we are willing to defend each choice.

Default 1: TLS-only public listeners

Anything reaching us across the public network terminates on port 8883 with TLS, or it does not connect. WSS on 443 follows the same rule. There is no plaintext fallback on a public listener. We do not auto-negotiate down. A client that arrives speaking TLS 1.0 or 1.1 is refused, not transparently downgraded. RC4 and 3DES are off. The cipher suites we accept are the modern set with perfect forward secrecy, and the floor moves up as the IETF and major browsers move it up.

Plaintext port 1883 still exists, because there are legitimate uses for it. A bare-metal deployment with the broker, the application, and the database on the same private network does not need TLS for the loopback hop, and we will not force a self-signed certificate ceremony on people who have a real reason to skip it. But 1883 is opt-in, never the default, and never reachable from the public internet on a CloudSignal-managed cluster. The choice we made is that “encrypted” is the unmarked case and “not encrypted” is the case you have to ask for.

Default 2: Deny-by-default ACLs

A new organisation on CloudSignal starts with an empty rule set. That is not a placeholder you fill in later. It is the security posture. No rule means no permission. The broker will accept the connection if the credential is valid and reject every publish and every subscribe until you tell it which topics this identity is allowed to touch.

This is the inversion of the pattern most brokers ship. The common setup hands a new tenant a rule that effectively says read and write everything under their namespace, and expects the operator to come back later and tighten it. In practice nobody comes back. The “we will lock that down before production” rule becomes the production rule. Deny-by-default removes the failure mode entirely. You cannot forget to constrain a permission that was never granted.

Operationally this means the first thing a new customer does is write rules. We give them five preset templates to start from (notifications, agent pipelines, chat channels, permit-all for prototyping, blank for the cautious), a policy simulator to test rules against real topic patterns before deploying, and a CLI for version-controlled deployment. The friction is real and we keep it deliberately low. The default stays deny.

Default 3: Per-org mountpoints

Every connection on our broker is scoped to its organisation through a mountpoint prefix. A client connects with a username like user_xyz@org_k7xm4pqr2n5t, and the broker silently prepends an org-specific prefix to every topic that client publishes to or subscribes to. The client never sees the prefix. From inside the connection, chat/room/42 is chat/room/42. From the broker’s perspective, that topic lives inside the org slice and cannot collide with, leak into, or be subscribed from any other org’s slice.

The consequence is that a credential leaked from organisation A is useless against organisation B’s topics even though both organisations share the same broker cluster, the same processes, and the same wire. The isolation is enforced by the broker on every operation, not by the application after the fact. If the application has a bug, the broker still holds the boundary.

This composes with the credential model we wrote about in an earlier post. Credentials are short-lived by default, so a leak is bounded by time. Credentials are org-scoped by mountpoint, so a leak is bounded by tenant. The two properties multiply rather than add. We picked them as a pair on purpose.

What we audit and what we don’t

We are deliberate about the line between protocol-layer security (ours) and application-layer security (yours), and the audit log reflects that line.

We log failed authentication attempts with reason codes, which lets you see whether a credential is expired, malformed, scoped to the wrong org, or simply unknown. We log ACL denials with the topic, the client, the action, and the rule (or absence of rule) that produced the verdict. We log connection origin IP, transport, MQTT version, and TLS cipher. We log session lifecycles: connect, subscribe, unsubscribe, clean disconnect, ungraceful disconnect. Compliance reviewers can answer “who connected, from where, when, and what were they allowed to do” without leaving our audit surface.

We do not inspect payload contents. We do not run PII detection on the bodies of messages. We do not log message content beyond size and routing metadata. That is the application’s responsibility, and we think trying to do it at the broker level would create a different and worse problem: a single tenant could accidentally cause us to retain regulated data, and customers would have no way to verify what the broker did or did not look at. The current line is predictable. You can describe it to an auditor in one sentence. We are keeping it.

What we want to add next

The next layer we are looking at is bring-your-own-CA, so enterprise customers can pin the broker’s leaf certificate to a private trust chain and rotate on their own cadence. After that, customer-managed encryption keys for the at-rest path, so a customer with a regulatory requirement to hold the key material can do so without us seeing it. Neither ships on a date we are willing to commit to publicly. Both are directions, not promises.

The bar we hold ourselves to is that the defaults already in place stay defaults. New capabilities are options. TLS-only, deny-by-default, and per-org mountpoints are not toggles we are going to soften under pressure from a single account. If we ever revisit any of the three, the reasoning will be in a post like this one.

Ready to get started?

Try CloudSignal free and connect your first agents in minutes.

Start Building Free