MQTT Fundamentals

Fixing "MQTT Connection Refused: Not Authorized" (rc 5 and 0x87)

Getting "Connection Refused: not authorised" or reason code 0x87? Work through this checklist covering credentials, client ID binding, ports and TLS, and per-broker accounts to find the cause quickly.

Broker rejecting a device login to illustrate the mqtt connection refused not authorized error
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

"MQTT connection refused: not authorized" means the broker received your CONNECT packet, understood it, and decided this client may not connect. In MQTT 3.1.1 that is CONNACK return code 5; in MQTT 5 it is reason code 0x87. This guide gives you a step-by-step checklist to find the cause, from credentials and client IDs to port mix-ups and per-broker accounts, and shows how to test each step from the command line.

What "Not Authorized" Actually Tells You

The error is more informative than it looks. To receive it at all, several things must already work:

  • DNS resolved the broker host.
  • The TCP connection, and TLS if used, was established.
  • The broker parsed a valid CONNECT packet.
  • The protocol version was accepted.

So the network is fine. The problem is identity or permission. You will see it worded in different ways depending on the tool:

Tool Typical message
mosquitto_pub / mosquitto_sub Connection error: Connection Refused: not authorised.
Paho Python 2.x reason_code equals Not authorized in on_connect
MQTT.js Connection refused: Not authorized (err.code === 5) or reason code 135 with MQTT 5
Node-RED MQTT node Status shows "connecting" and the log reports connection refused, not authorized

A related code is worth separating early. Return code 4 (0x86 in MQTT 5) means "bad user name or password": the credentials themselves did not match. Code 5 (0x87) is broader: the broker refuses this client for an authorization reason. Some brokers return 5 for wrong passwords too, so treat both as "check identity" but read the exact code. The MQTT CONNACK return codes guide explains every value.

The Not Authorized Troubleshooting Checklist

Work through these steps in order. Most cases are solved by step 3.

  1. Confirm which broker you are connecting to. Print the host and port your code actually uses at runtime, not the one you think is configured. Environment variables and config files frequently override each other.
  2. Re-copy the credentials. Paste username and password fresh from the broker's credential page. Check for leading or trailing spaces, line breaks from copying, and username and password swapped.
  3. Use the client ID that belongs to the credentials. Many managed brokers bind a client ID to the issued account. If your code generates a random ID or reuses one from another project, the broker can refuse it even though the password is correct.
  4. Check that the library sends credentials. In Paho, username_pw_set() must be called before connect(). In Arduino PubSubClient, use the connect(clientId, user, pass) overload, not connect(clientId).
  5. Check shell quoting. Passwords containing $, ! or & get mangled by Bash. Use single quotes: -P 'p@ss$word!'.
  6. Verify the port and transport. Port 1883 is plain TCP, 8883 is TLS, 8083 is WebSocket and 8084 is secure WebSocket with path /mqtt. A mismatch usually produces a timeout or TLS error rather than "not authorized", but a misconfigured client can end up talking to a different listener or environment than intended.
  7. Confirm the account is active. Credentials may have been regenerated, a broker deleted or recreated, or you may be using staging credentials against production.
  8. Check connection quotas. If the plan's connection limit is reached, MQTT 5 clients get 0x97 Quota exceeded, but some 3.1.1 libraries surface any refusal generically. Count your active connections.
  9. Stop retrying in a loop. Each failed attempt is a failed login from the broker's perspective. Back off while you investigate.

Testing Credentials from the Command Line

Isolate your application from the problem by testing the exact same credentials with Mosquitto's tools. First, prove the network path works with the anonymous public MQTT test broker:

mosquitto_sub -h broker.connectmq.com -p 1883 -i auth-check-2d9f \
  -t "connectmq/demo/2d9f/#" -d -C 1 -W 5

If you see received CONNACK (0), your machine can reach the broker and speak MQTT. Next, test your private credentials over TLS:

mosquitto_sub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
  -u 'YOUR_USERNAME' -P 'YOUR_PASSWORD' -i 'YOUR_CLIENT_ID' \
  -t "test/#" -d -V mqttv5

With -V mqttv5, a refusal prints the MQTT 5 reason code, which is more specific than the 3.1.1 code. If this command connects but your application does not, the problem is in your application's configuration, not the account. If this command also fails, the problem is the credentials, client ID or account.

On Windows, --capath is not available in the same form; use --cafile with a CA bundle file instead, or test with an MQTT GUI client.

Fixing It in Code

Here is a Python client that prints the configuration it is really using and stops on authorization errors instead of retrying forever:

import os
import ssl
import paho.mqtt.client as mqtt

HOST = os.getenv("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.getenv("MQTT_PORT", "8883"))
USERNAME = os.getenv("MQTT_USERNAME", "YOUR_USERNAME")
PASSWORD = os.getenv("MQTT_PASSWORD", "YOUR_PASSWORD")
CLIENT_ID = os.getenv("MQTT_CLIENT_ID", "YOUR_CLIENT_ID")

print(f"Connecting to {HOST}:{PORT} as user={USERNAME!r} client_id={CLIENT_ID!r}")

def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Refused: {reason_code} (0x{reason_code.value:02X})")
        if reason_code.value in (0x85, 0x86, 0x87):
            print("Identity problem: check username, password and client ID")
            client.disconnect()
        return
    print("Connected")

client = mqtt.Client(
    mqtt.CallbackAPIVersion.VERSION2,
    client_id=CLIENT_ID,
    protocol=mqtt.MQTTv5,
)
client.username_pw_set(USERNAME, PASSWORD)
client.tls_set(cert_reqs=ssl.CERT_REQUIRED)
client.on_connect = on_connect
client.connect(HOST, PORT, keepalive=60)
client.loop_forever()

The !r formatting prints values with quotes, which makes invisible whitespace obvious. That one line has solved many "my password is definitely right" investigations.

For an ESP32 with PubSubClient, the common mistake is the overload:

// Wrong: no credentials are sent
mqtt.connect("YOUR_CLIENT_ID");

// Right: client ID, username and password
mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD");

Not Authorized After Connecting

Sometimes the connection succeeds but later operations fail with "not authorized". In MQTT 5 you will see 0x87 in a SUBACK or PUBACK, or in a DISCONNECT. That means the client may connect but is not allowed to use a specific topic, for example a reserved prefix. With MQTT 3.1.1 there is no reason code for a rejected publish, so the message may simply disappear. If messages vanish, connect with MQTT 5 temporarily to see the actual reason code. The MQTT reason codes reference lists every code by packet type.

How This Works on ConnectMQ

On ConnectMQ, each broker you create in the portal gets a generated username, password and client ID, and the client ID is bound to those credentials. That is the first thing to check when you see 0x87: are you using all three values from the same broker? Brokers are isolated per tenant, so credentials from one broker will not work on another, even within the same account.

Two more platform behaviours are worth knowing:

  • Failed logins are rate-limited. After repeated failed logins, the source IP address is blocked. A device stuck in a tight reconnect loop with stale credentials can lock out other devices behind the same NAT. Use exponential backoff.
  • Connection limits are per plan. The free Serverless plan allows up to 25 concurrent connections. Exceeding it produces 0x97 Quota exceeded for MQTT 5 clients, not "not authorized", which is one reason to prefer MQTT 5 while debugging.

For hardening beyond authentication, see the MQTT security best practices, and the MQTT tutorial for the wider protocol picture.

Connect Securely with ConnectMQ

A hosted MQTT broker that issues matching credentials and client IDs removes most causes of this error before they happen. Sign up at app.connectmq.com for a free Serverless broker with no credit card, and use the in-browser MQTT client to confirm your credentials work before you flash a single device. Learn more about running a cloud MQTT broker.

Frequently Asked Questions

What does "Connection Refused: not authorised" mean in Mosquitto tools?

It is CONNACK return code 5. The broker received a valid CONNECT but refused the client, usually because of wrong credentials, a client ID not bound to the account, or credentials for a different broker.

Is "not authorized" the same as "bad username or password"?

Not exactly. Bad username or password is code 4 (0x86) and means the credentials did not match; not authorized is code 5 (0x87) and covers wider permission problems. Some brokers use code 5 for both, so check credentials first either way.

Why does my client connect with mosquitto_sub but not from my app?

The app is sending something different: another host, a generated client ID, missing credentials or a mangled password. Print the effective configuration at runtime and compare it with the working command.

Can repeated failed logins cause problems?

Yes. Many brokers, including ConnectMQ, block IP addresses after repeated failed logins. Use exponential backoff and stop retrying on authorization errors.

Related articles

Why Your MQTT Client Keeps Disconnecting (and How to Fix It)

Reconnect loops are one of the most common MQTT problems. Learn the five usual causes, from duplicate client IDs to keep alive timeouts and oversized packets, and follow a diagnosis flow that pinpoints yours.

8 min read

Who Invented MQTT? The History from Oil Pipelines to IoT

MQTT was invented in 1999 by Andy Stanford-Clark of IBM and Arlen Nipper of Arcom to monitor oil pipelines over satellite. Follow its path to open source, OASIS, ISO and today's managed cloud brokers.

7 min read

MQTT Maximum Message Size: Limits and Large Payload Strategies

MQTT can technically carry a 256 MB packet, but brokers, client libraries and devices impose far lower limits. Learn where the real limits are, what happens when you exceed them, and how to send large payloads.

7 min read

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.