Blog

Debugging MQTT TLS and mTLS Connections

Why secure MQTT connections fail and how to fix them: expired chains, hostname mismatches, wrong ALPN, and mutual-TLS errors — diagnosed stage by stage on iOS.

May 21, 2026

How a Secure MQTT Connection Is Established

Three distinct layers must succeed in order before a single MQTT message can flow.

TCP. The client resolves the broker hostname, opens a socket on port 8883 (MQTT/TLS) or 443/8084 (WebSocket/TLS), and completes the three-way handshake. Failures here are network issues, not TLS or MQTT issues.

TLS handshake. With a socket open, client and server negotiate a cipher suite, exchange certificates, and establish an encrypted channel. This is where most secure-MQTT failures occur: certificate chain validation, hostname verification, ALPN negotiation, and in mTLS setups, client certificate authentication.

MQTT CONNECT. Only after TLS succeeds does the MQTT protocol begin. The client sends CONNECT; the broker replies with CONNACK. A non-zero reason code here is an application-level rejection — credentials wrong, authorization denied, client ID invalid — not a TLS problem.

Pinning down which layer failed determines the right fix. The Connection Doctor runs staged diagnostics (DNS → TCP → TLS → WebSocket → MQTT → Subscription) and names the failing stage with a plain-language cause and remedy.


Common TLS Failures

Expired or Incomplete Certificate Chain

The broker’s leaf certificate has an expiry date, and so does every intermediate CA. An expired intermediate breaks connections even when the leaf cert is current.

TLS handshake error: certificate has expired or is not yet valid
TLS handshake error: unable to verify the first certificate

Import the full PEM chain (leaf → intermediates → root CA) in the Certificate Wizard; its built-in validator flags any certificate outside its validity window before you connect.

Hostname / SAN Mismatch

TLS clients verify that the connected hostname matches a SAN (Subject Alternative Name) entry in the server certificate, or the CN field as a fallback. An exact match is required.

TLS handshake error: hostname "broker.example.com" does not match CN "mqtt.example.com"

Connect using the exact hostname in the SAN, or use the SNI override in the Certificate Wizard to send the correct server name during the handshake without changing your connection address.

Untrusted or Self-Signed CA

Private brokers — Mosquitto on a Raspberry Pi, internal test environments, AWS IoT custom endpoints — often use certificates signed by a private CA that iOS doesn’t trust by default.

TLS handshake error: self signed certificate in certificate chain

Import your private CA’s root certificate as a PEM file in the Certificate Wizard. The wizard shows its SHA-256 fingerprint so you can verify you’re trusting the right authority. Certificate material is stored in the iOS Keychain, not in app storage.

Wrong or Missing ALPN

Some brokers use ALPN to route MQTT on shared ports. AWS IoT Core accepts MQTT on port 443 only when the client advertises x-amzn-mqtt-ca in the ALPN extension. Omitting it produces a TLS alert that resembles a certificate failure.

TLS handshake error: tlsv1 alert internal error

Open the ALPN list in the Certificate Wizard and add the identifier your broker requires. The AWS IoT guide covers the exact values. For standard MQTT over TLS on 8883, no ALPN entry is usually needed.

Unsupported TLS Version

iOS 15 and later reject TLS 1.0 and 1.1 at the system level. Some hardened brokers require TLS 1.3 and reject older negotiation. Either situation produces:

TLS handshake error: unsupported protocol

This is a server-side configuration issue. Update the broker to accept TLS 1.2 or 1.3.


Mutual TLS (mTLS): Client Certificate Authentication

Standard TLS only authenticates the server. Mutual TLS requires both parties to present and verify certificates — common in AWS IoT Core device provisioning, industrial IoT, and enterprise deployments.

What You Need

  • Client certificate — issued to your device or service account
  • Client private key — the private key corresponding to the client certificate
  • CA certificate — the authority that signed both the client and server certificates

These arrive as a .p12/.pfx bundle (certificate + key, passphrase-protected) or as separate PEM files. The Certificate Wizard accepts both and stores everything in the iOS Keychain.

Common mTLS Errors

Passphrase mismatch on a .p12 bundle. Import fails with “incorrect passphrase.” Passphrases are case-sensitive; re-export from your CA if you’ve lost the correct value.

Client cert and private key don’t match. The Certificate Wizard validates the key-to-certificate correspondence before saving, surfacing a warning rather than letting a mismatched pair cause a cryptic runtime failure:

TLS handshake error: private key does not match public key

Handshake succeeds but broker disconnects immediately. This is a broker-side authorization failure. In AWS IoT Core it typically means the certificate’s Thing Policy doesn’t grant iot:Connect for the client ID being presented. Inspect the CONNACK reason code — 0x87 means “not authorized.”


Staged Diagnostics and CONNACK Reason Codes

The Connection Doctor stops at the first failing stage and reports exactly what went wrong:

StageFails When
DNSHostname won’t resolve — typo, VPN routing, split-horizon
TCPPort unreachable — firewall, wrong port, broker down
TLSHandshake error — chain, hostname, ALPN, CA trust
WebSocketHTTP Upgrade fails — wrong path, missing headers
MQTTCONNACK non-zero — credentials, client ID, protocol version
SubscriptionSubscribe rejected — ACL, wildcard denied

If the TLS handshake succeeds but the session drops at the MQTT stage, read the CONNACK reason code. Common codes:

CodeMeaning
0x87Not authorized — ACL or IoT policy denies iot:Connect
0x86Bad username or password
0x85Client identifier not valid

The Connection Doctor decodes these codes into plain-language messages, and any diagnostic bundle you share has secrets redacted automatically.


Practical Checklist

  • Port is correct: 8883 (MQTT/TLS), 8084 (MQTT/WSS), 443 (ALPN routing)
  • Server certificate chain is complete and all certs are unexpired
  • Connection hostname matches a SAN entry (or CN) in the server certificate
  • Private CA root is imported and trusted
  • ALPN value is set if the broker requires it (e.g., x-amzn-mqtt-ca for AWS IoT on 443)
  • For mTLS: client certificate, private key, and CA are all present; passphrase is correct
  • Client cert private key matches the certificate’s public key
  • Broker policy grants Connect for this client ID

For the full connection workflow on iOS, see the MQTT on iPhone guide. MQTT Commander for iOS is a $2.99 one-time purchase with the Certificate Wizard and Connection Doctor built in.

← All guides

Debug MQTT on your iPhone

MQTT Commander brings this workflow to iOS and iPadOS.

Coming soon to theApp Store

Coming soon to the App Store · $2.99