Blog

Connect to AWS IoT Core MQTT from iOS

Test AWS IoT Core from your iPhone: import a device certificate and key, set the x-amzn-mqtt-ca ALPN protocol, and connect over mutual TLS to publish and subscribe.

May 26, 2026

AWS IoT Core and Mutual TLS

AWS IoT Core requires every connecting device to authenticate with a client certificate signed by AWS, rather than a username and password. This design, known as mutual TLS (mTLS), means the broker verifies the client and the client verifies the broker in the same TLS handshake. The standard endpoints offer no way to disable it.

For embedded firmware running on a microcontroller, the SDK manages those certificates. On a laptop you might load them into Mosquitto or the AWS IoT Device Client. On an iPhone, you need an MQTT client that understands PEM certificates, stores secrets in the iOS Keychain, and lets you tune the ALPN extension. MQTT Commander does all three.

What You Need Before You Start

  • ATS endpoint: in the AWS IoT console, open Settings and copy the Device data endpoint. It looks like <prefix>-ats.iot.<region>.amazonaws.com. The -ats suffix matters, because AWS is retiring the legacy VeriSign endpoint.
  • Device certificate (certificate.pem.crt): you create it when you register a Thing or use the IoT console’s one-click certificate wizard.
  • Private key (private.pem.key): AWS generates it alongside the certificate. AWS does not store the private key server-side; if you lost it, revoke the certificate and create a new one.
  • Root CA (optional but recommended): iOS already trusts Amazon’s ATS root CA, and importing it anchors trust to that CA and lets MQTT Commander verify the client certificate’s expiry and hostname (SAN/CN) for you.
  • IoT policy: a policy attached to the certificate that grants iot:Connect, iot:Publish, and iot:Subscribe for the topics you intend to use.

A minimal policy for testing looks like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:Connect",
        "iot:Publish",
        "iot:Subscribe",
        "iot:Receive"
      ],
      "Resource": "arn:aws:iot:<region>:<account-id>:*"
    }
  ]
}

Scope it down to specific topic ARNs before using it in production.

Importing the Certificate and Key into MQTT Commander

MQTT Commander’s Certificate Manager stores credentials in the iOS Keychain. They never leave the device, and nothing syncs to iCloud or an external server.

  1. Transfer your credentials to your iPhone: the Amazon root CA as a PEM and your client identity as a .p12 / .pfx bundle. AirDrop, the Files app, or a share sheet from Safari all work.
  2. In MQTT Commander, open the Connections tab and tap + to create a new connection, or open an existing one and go to TLS Settings.
  3. Tap Certificate ManagerImport Certificate.
  4. Provide the credentials:
    • CA Certificate: paste or load the Amazon root CA as a PEM (optional if you rely on system trust).
    • Client identity: import the client certificate and private key together as a .p12 / .pfx bundle; a standalone PEM private key is not supported. Bundle certificate.pem.crt and private.pem.key with OpenSSL (openssl pkcs12 -export -in certificate.pem.crt -inkey private.pem.key -out client.p12), then switch to PKCS#12 mode and supply the bundle password.
  5. Tap Validate. The Certificate Manager checks the certificate’s expiry, SAN/CN hostname, and SHA-256 fingerprints and reports any issues before you attempt a connection.

Port 8883 vs. Port 443 and the ALPN Extension

AWS IoT Core listens for MQTT over two ports:

PortProtocolALPN required
8883MQTT over TLSNone (or mqtt)
443MQTT over TLS via ALPNx-amzn-mqtt-ca

Port 8883 is the traditional MQTT/TLS port. Many corporate firewalls block it. Port 443 stays open for HTTPS traffic on most networks, which is why AWS supports MQTT on it via the ALPN extension: the client advertises x-amzn-mqtt-ca in the TLS ClientHello, and the server hands off to the MQTT broker instead of an HTTPS handler.

To configure this in MQTT Commander:

  • Host: <prefix>-ats.iot.<region>.amazonaws.com
  • Port: 443 (or 8883)
  • TLS: enabled, with the certificate profile you just imported
  • ALPN: in the Advanced TLS section, add x-amzn-mqtt-ca to the ALPN protocol list
  • SNI: leave it set to the hostname; AWS requires SNI to route the connection

If you are on a network that blocks 8883 and you forget to set the ALPN on port 443, the TLS handshake will complete and AWS will close the connection. The Connection Doctor surfaces this as a TLS-layer drop rather than a silent timeout.

Connecting and Running Your First Test

With the certificate imported and ALPN configured, tap Connect. MQTT Commander runs through its staged diagnostics: DNS resolution → TCP handshake → TLS handshake (including mTLS certificate exchange) → MQTT CONNECT → CONNACK.

A successful CONNACK with return code 0 (Connection Accepted) means AWS authenticated your device certificate, matched it to an active certificate record, and found a policy that allows iot:Connect for your client ID.

Subscribe first, then publish:

  1. Tap Subscribe and enter a topic your policy allows, for example devices/my-phone/status.
  2. Tap Publish, set the same topic, and send a JSON payload:
{
  "temperature": 22.5,
  "unit": "C",
  "timestamp": 1716768000
}

The message should appear in the subscriber pane. You can also open the AWS IoT console’s MQTT test client on your laptop and subscribe to the same topic to confirm messages are flowing end-to-end.

Common Errors and How Connection Doctor Surfaces Them

Policy Denies the Action

CONNACK return code 5 (Not Authorized) or, in MQTT 5.0, reason code 0x87 (Not Authorized). The certificate authenticated, but the attached policy does not grant the required action (iot:Connect, iot:Publish, etc.) for the resource ARN. Check the policy in the AWS console and confirm the certificate is Active and the policy is attached to the certificate (not just to the Thing).

Wrong ALPN on Port 443

If you connect on port 443 without x-amzn-mqtt-ca in the ALPN list, the AWS load balancer treats it as HTTPS and returns an HTTP 400 or closes the socket. Connection Doctor flags this at the TLS stage as an unexpected socket close, not at the MQTT stage, which narrows the search.

Hostname Mismatch / SNI Missing

Using an IP address instead of the ATS hostname, or disabling SNI, causes the TLS handshake to fail with a certificate verification error. AWS IoT Core presents a certificate for the hostname, so SNI must carry the correct hostname. MQTT Commander enables SNI by default and lets you override it only when you have a deliberate reason (for example, testing behind a reverse proxy).

Expired or Revoked Certificate

If the device certificate has been deactivated or revoked in the AWS console, the CONNACK will return Not Authorized. The Certificate Manager warns you at import time if the certificate’s notAfter date has already passed, which saves a round-trip to AWS.

Testing Across Environments

Testing AWS IoT from an iPhone lets you validate connectivity over a cellular network, with no corporate VPN and no local Wi-Fi routing quirks in the way. That gives you a clean signal that your policy and endpoint work for real devices in the field.

For a deeper look at TLS certificate formats, chain validation, and how to debug mTLS handshake failures in general, see the companion post MQTT TLS and mTLS Debugging. If you are new to running MQTT from a phone, MQTT on iPhone covers the basics of setting up your first connection.

MQTT Commander is free to download for iOS and iPadOS 17+, with an optional $4.99 one-time Pro unlock and no subscription and no data leaving your device beyond anonymous crash diagnostics.

← All guides

Debug MQTT on your iPhone

MQTT Commander brings this workflow to iOS and iPadOS.

Free · Pro unlock $4.99, one-time