MQTT over TLS: A Practical Guide to Certificates and Configuration

A practical walkthrough of MQTT over TLS: what TLS actually secures, when broker vs. client certificates are needed, and how to inspect a broker's certificate from the command line.

Running MQTT over TLS — commonly shortened to MQTTs — is, at its core, MQTT wrapped in the same kind of protection HTTPS gives the web. That raises two practical questions worth answering before you flip the switch: what exactly do you need to think about when enabling TLS, and when do you actually need certificates — for the broker, for clients, or both?

What TLS actually gives you

Turning on TLS for your broker gets you three things:

  • Confidentiality — payloads and topic names are encrypted in transit.
  • Integrity — messages can’t be modified in transit without it being detected.
  • Authentication — you can be confident you’re talking to the real broker, and optionally prove the client’s identity too.

You can run MQTT over TLS directly (typically port 8883) or over WebSockets plus TLS (often port 443). The certificate story is identical either way.

When certificates are actually needed

The broker (server) certificate — almost always

With standard, public-key-based TLS, the broker always needs a certificate. It holds a private key (kept secret) and presents a server certificate (the public part) issued by some CA. The client uses that certificate to verify it’s talking to the real broker — a hostname check — and to negotiate the encrypted connection.

MQTT over TLS means the broker needs a certificate, full stop. The only real exception is PSK (pre-shared key) ciphers, and support for those is spotty enough across MQTT clients that it’s rarely worth the reduced flexibility.

What about the client, in this basic case? Clients don’t need their own certificate here — they just need to trust the CA that signed the broker’s certificate, and can optionally authenticate themselves with a username/password or token sent over the now-encrypted connection. Use a public CA (Let’s Encrypt, for instance) for internet-reachable brokers, and a private or internal CA for internal infrastructure.

Client certificates (mutual TLS) — only for strong device identity

Client certificates come into play specifically when mutual TLS (mTLS) is enabled. In that setup, the broker still has its usual server certificate, but clients each carry their own private key and certificate, signed by a CA the broker trusts.

Enable mTLS when you want strong, hardware-tied device identity — common in enterprise and IoT contexts — when you’d rather not manage passwords or tokens at all, and when the broker should authenticate devices by certificate alone.

In that configuration:

  • The broker needs its own server certificate and key, plus the CA certificate(s) used to verify client certificates, and optionally maps client certificate subjects (CN, SAN) to MQTT client IDs and permissions.
  • The client needs the CA certificate that issued the broker’s certificate (to verify the broker), plus its own client certificate and private key (to present to the broker).

The short version: client certificates are only needed when mutual TLS or explicit certificate-based client authentication is the goal. Server certificates are needed for any standard TLS setup, full stop.

Self-signed vs. CA-signed

Three real options for the broker’s certificate:

  1. Public CA (e.g. Let’s Encrypt) — good for internet-facing brokers. Clients typically already trust these root CAs, but make sure the certificate uses the correct hostname (CN/SAN) and that clients connect using that hostname rather than a raw IP, or verification will fail.
  2. Private CA (your own PKI) — good for large device fleets and internal systems. You create your own CA, sign broker and client certificates with it, and distribute the CA root certificate to every client.
  3. Pure self-signed certificate — the broker’s certificate signs itself, with no CA involved. Every client has to trust that exact certificate or its fingerprint directly. Fine for small lab setups, internal demos, and prototypes — hard to manage at scale or across key rotations.

Practical considerations once TLS is on

TLS version and ciphers. Use TLS 1.2 or 1.3 only, and disable 1.0/1.1. Most brokers ship with secure cipher defaults now. On constrained devices, actually test handshake speed and RAM/flash usage — TLS adds CPU and memory overhead versus plain MQTT, but it’s usually acceptable if connections stay open rather than reconnecting constantly.

Hostname and certificate validation. Always enable certificate verification on clients — don’t skip it “for dev convenience,” because that habit has a way of surviving into production. Make sure the broker’s hostname in the certificate actually matches what the client connects to: a certificate for mqtt.example.com requires clients to connect to mqtt.example.com, not its raw IP. On the broker side, if mutual TLS is enabled, decide which CAs are allowed to sign client certificates and how client certificate identity maps to MQTT auth and ACLs.

Authentication strategy. A few common patterns:

  • TLS + username/password — clients trust the broker’s CA and send credentials over the encrypted connection. Simple to manage, common for generic applications.
  • TLS + token (JWT, SAS, etc.) — same shape, but with a short-lived token instead of a traditional password.
  • Mutual TLS only — no username/password at all; identity is the client certificate’s subject. A good fit for devices that can store keys securely in a TPM or secure element.
  • Mixtures — mTLS plus a token, for example, if the broker and client library support layering them.

Connection behavior and performance. TLS adds handshake cost at connection setup and a small per-packet overhead. In practice this means keeping connections long-lived where possible, using keep-alives and persistent sessions to avoid reconnect storms, and — for large device fleets — staggering connections rather than having everything reconnect at once, and using TLS session resumption where supported to speed up reconnects.

Certificate lifecycle. This is the big operational topic that’s easy to underestimate. Certificates expire — set up monitoring and automated renewal (Let’s Encrypt makes this straightforward). Plan for rotation: rolling out new CA or broker certificates, and revoking compromised client certificates. On brokers, restrict file permissions on key material; on clients and devices, use secure storage — a TPM or secure element — wherever the hardware supports it. For any fleet running mTLS, a proper PKI and provisioning story stops being optional and becomes the thing that determines whether the whole approach is sustainable.

A quick mental checklist

When someone says “I want MQTT over TLS,” it’s worth walking through:

  1. Is the broker running TLS 1.2+ with a proper certificate? (Yes, always — from a public or private CA.)
  2. Do you need to strongly identify each device or client? If yes, mutual TLS and client certificates. If no, server-only TLS with username/password or a token is fine.
  3. Are clients actually verifying the broker’s hostname and CA? They should be — always.
  4. Is there a plan for certificate renewal and rotation? Especially critical if you’re running your own CA or mTLS.

Checking a broker’s certificate from the command line

Sometimes the fastest way to understand what’s actually configured is to just look. openssl s_client connects and dumps the full certificate chain:

openssl s_client -connect mqtt.example.com:8883 -showcerts

The output includes the server certificate, any intermediate CA certificates, and details like subject, issuer, validity dates, SAN hostnames, public key type, and signature algorithm. A real run against a public broker looks like this:

Connecting to 46.137.47.218
CONNECTED(000001C8)
depth=2 C=US, O=Internet Security Research Group, CN=ISRG Root X1
verify return:1
depth=1 C=US, O=Let's Encrypt, CN=R12
verify return:1
depth=0 CN=*.s1.eu.hivemq.cloud
verify return:1
---
Certificate chain
 0 s:CN=*.s1.eu.hivemq.cloud
   i:C=US, O=Let's Encrypt, CN=R12
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Oct 19 18:14:29 2025 GMT; NotAfter: Jan 17 18:14:28 2026 GMT
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
 1 s:C=US, O=Let's Encrypt, CN=R12
   i:C=US, O=Internet Security Research Group, CN=ISRG Root X1
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Mar 13 00:00:00 2024 GMT; NotAfter: Mar 12 23:59:59 2027 GMT
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
---
Server certificate
subject=CN=*.s1.eu.hivemq.cloud
issuer=C=US, O=Let's Encrypt, CN=R12
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 3082 bytes and written 459 bytes
Verification: OK
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES128-GCM-SHA256
    Session-ID: 0B1CBC4AF221BADAD850E36F2B9321EC4563CC361F65B6F69B3888B9A8A7C791
    Session-ID-ctx:
    Master-Key: 8605B976F3C76A389937BA9DCA415490A4BB062B430F6A24AD26CEB5C871A41F1F487D6E28748A07718B45C459189634
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1764700006
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: yes
---
closed

To inspect a single certificate more readably, copy the -----BEGIN CERTIFICATE----- / -----END CERTIFICATE----- block out into broker.pem and run:

openssl x509 -in broker.pem -text -noout

That gives a clean, structured breakdown — subject, issuer, validity window, public key details, extensions, and the signature itself.

A third option, useful when you don’t have or want credentials handy: mosquitto_sub performs the TLS handshake before authentication is checked, so you can pull the certificate even from a failed subscription attempt:

mosquitto_sub -h mqtt.example.com -p 8883 --show-certificates -t test

This prints the certificate subject, issuer, validity period, and SHA-1/SHA-256 fingerprints — enough to confirm what’s actually deployed without needing a valid login.

The takeaway

MQTT over TLS is conceptually simple — confidentiality, integrity, and broker authentication, with optional client authentication layered on top via mutual TLS. The complexity lives entirely in the operational details: certificate issuance, hostname matching, rotation, and making sure clients are actually verifying what they’re supposed to verify. Get those right once, and the security model does exactly what it promises.