MQTT Fundamentals

MQTT Client ID Best Practices: Uniqueness, Format and Takeovers

The client ID is how an MQTT broker knows who you are. Get it wrong and devices kick each other offline or lose their sessions. Here are the rules, formats and debugging steps that work.

MQTT client ID illustration showing two devices with the same identifier competing for one broker connection
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

The MQTT client ID is the identifier a client sends in CONNECT, and the broker uses it to tell connections and sessions apart. This guide explains why two clients with the same ID keep disconnecting each other, how to design ID formats that scale from one prototype to a fleet, and how to diagnose takeovers quickly when testing on a public broker.

What the MQTT Client ID Is Used For

Every CONNECT packet carries a Client Identifier field. The MQTT broker uses it for three things:

  1. Connection uniqueness. Only one network connection per client ID may be active at a time.
  2. Session lookup. Persistent session state (subscriptions and queued messages) is stored under the client ID.
  3. Operations. Logs, connection events and monitoring topics refer to clients by ID.

It is not an authentication credential by itself. Anyone who can connect can claim any ID unless the broker binds IDs to credentials. On ConnectMQ private brokers, client IDs are bound to the credentials issued in the portal, so a different user cannot reuse your device's ID.

Why Duplicate Client IDs Kick Each Other Off

The specification is explicit: if a client connects with an ID that is already connected, the broker must disconnect the existing client. This is called a session takeover. It exists so that a device that silently lost its connection can reconnect immediately without waiting for the old socket to time out.

The problem appears when two different clients share an ID. The sequence goes like this:

  1. Client A connects as sensor-01.
  2. Client B connects as sensor-01. The broker disconnects A.
  3. A's auto-reconnect fires and connects as sensor-01. The broker disconnects B.
  4. B reconnects... and the loop repeats every few seconds.

Symptoms include constant connect/disconnect logs, missed messages, will messages fired repeatedly, and an "online/offline" indicator that flickers. In MQTT 5 the kicked client receives a DISCONNECT with reason code 0x8E (Session taken over), which makes diagnosis much easier than in 3.1.1, where the socket simply closes.

Common Causes

  • The same firmware image flashed to many boards with a hard-coded ID.
  • Copy-pasted example code with an ID such as test or esp32client.
  • A service running in several containers or pods with the same configured ID.
  • A developer running the same script in two terminals.
  • A desktop MQTT tool and a device both using the device's ID.

Designing an MQTT Client ID Format

Good IDs are unique, stable, readable and safe for every broker.

Format Rules

Rule Why
Use only a-z, A-Z, 0-9, - and _ Every broker must accept these characters
Keep it short, ideally 23 characters or fewer MQTT 3.1.1 only guarantees support up to 23 bytes; most brokers allow more
Never leave it empty in production Empty IDs prevent persistent sessions, and many brokers reject them
Make it stable for devices with sessions A changing ID means a new session every time
Make it unique per running instance Prevents takeover loops
Avoid secrets and personal data IDs appear in logs and monitoring

Patterns That Work

  • Devices: a prefix plus a hardware-derived identifier, such as env- plus the last bytes of the MAC address (env-a4cf12b3), or a serial number from your manufacturing database.
  • Backend services: service name plus instance identifier, such as alarm-worker-0 from a StatefulSet ordinal. If instances are fully interchangeable and do not need sessions, a random suffix is fine.
  • Browser dashboards: a prefix plus a random string per tab, with clean sessions, because nobody needs to resume a dashboard's session.
  • Test scripts: a random suffix every run, for example test- plus 6 random hex characters.

Generating IDs in Code

Python, using the MAC address for a stable device ID or a random token for test clients:

import secrets
import uuid
import paho.mqtt.client as mqtt

def device_client_id(prefix: str = "env") -> str:
    mac = uuid.getnode()            # 48-bit hardware address as an int
    return f"{prefix}-{mac:012x}"   # e.g. env-a4cf12b3c4d5

def test_client_id(prefix: str = "test") -> str:
    return f"{prefix}-{secrets.token_hex(3)}"  # e.g. test-9f2c1a

client_id = device_client_id()
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id=client_id,
                     protocol=mqtt.MQTTv5)
print("Using client ID:", client_id)

ESP32 with PubSubClient, deriving the ID from the efuse MAC:

#include <WiFi.h>
#include <PubSubClient.h>

WiFiClient net;
PubSubClient mqttClient(net);

String makeClientId() {
  uint64_t mac = ESP.getEfuseMac();
  char id[24];
  snprintf(id, sizeof(id), "env-%04x%08x",
           (uint16_t)(mac >> 32), (uint32_t)mac);
  return String(id);
}

void connectMqtt() {
  String clientId = makeClientId();
  mqttClient.setServer("broker.connectmq.com", 1883);
  while (!mqttClient.connected()) {
    if (mqttClient.connect(clientId.c_str())) {
      Serial.println("Connected as " + clientId);
    } else {
      Serial.printf("Failed, state=%d. Retrying in 5 s\n", mqttClient.state());
      delay(5000);
    }
  }
}

The full board setup, including Wi-Fi, is in the ESP32 MQTT tutorial.

Empty Client IDs and Assigned Identifiers

MQTT 3.1.1 allows a zero-length client ID only with clean session set to true; the broker then invents one internally. MQTT 5 goes further: the broker returns an Assigned Client Identifier in CONNACK so the client knows its name. This is handy for throwaway clients, but it rules out persistent sessions, because you cannot reconnect as an identity you do not control. Many brokers, including the ConnectMQ public broker, simply require a non-empty ID, which is the safer habit anyway.

How to Detect a Client ID Takeover

Here is a reproducible test on the public MQTT test broker. Use your own random suffix and remember that the public area is readable by everyone.

  1. In terminal one, connect with an ID and debug output:
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
  -i dup-demo-k7q1 -d -t 'connectmq/demo/k7q1/#'
  1. In terminal two, run the exact same command.
  2. Terminal one is disconnected immediately; with -d you can see the broker close its connection. Depending on your mosquitto version it either exits or reconnects, in which case the two terminals start kicking each other off, which is exactly the loop described above.
  3. In a third terminal, watch the broker's view of that client:
mosquitto_sub -h broker.connectmq.com -p 1883 -i watcher-k7q1 -v \
  -t '$SYS/broker/connection/dup-demo-k7q1/state'

In production, a quick checklist when devices flap:

  1. Collect client IDs from all suspect devices and look for duplicates.
  2. Check whether disconnect reason codes show 0x8E (session taken over).
  3. Compare connection state changes with each device's reconnect timestamps; alternating patterns reveal a pair fighting over one ID.
  4. Close desktop tools or VS Code sessions that might be using a device's ID.
  5. If flapping continues with unique IDs, look at keep alive and network timeouts instead.

MQTT Client IDs in Production

A few operational habits prevent most client ID incidents. Generate IDs at provisioning time rather than at runtime, so the same device always gets the same ID even after a factory reset. Store the ID next to the device's credentials so support staff can match log entries to hardware. When you replace a broken unit, decide deliberately whether the new device inherits the old ID (and its session) or gets a fresh one. For services, make the instance identifier come from your orchestrator rather than from a config file that every replica shares.

As fleets grow, treat client IDs as part of your provisioning process: record them alongside serial numbers, derive them from hardware, and never reuse an ID for a different physical device. If you are learning MQTT from scratch, the MQTT tutorial explains how IDs, sessions and topics fit together.

Manage Client IDs Safely with ConnectMQ

ConnectMQ is a fully managed MQTT service that issues a username, password and client ID for each broker you create, and binds client IDs to those credentials so other tenants cannot hijack them. Connection state is visible live in the portal, which makes takeover loops easy to spot. Create a free Serverless broker with no credit card and connect using YOUR_USERNAME, YOUR_PASSWORD and YOUR_CLIENT_ID.

Frequently Asked Questions

What happens if two MQTT clients use the same client ID?

The broker disconnects the client that was already connected and keeps the new one. If both clients auto-reconnect, they keep kicking each other off in a loop.

How long can an MQTT client ID be?

MQTT 3.1.1 guarantees support for 1 to 23 bytes of letters and digits, and brokers may allow longer IDs and more characters. Keeping IDs short and alphanumeric with hyphens is the most portable choice.

Should the MQTT client ID be random?

Use a random ID for short-lived or interchangeable clients that do not need sessions. Devices and services that rely on persistent sessions need a stable, unique ID that stays the same across reconnects.

Is the client ID a security credential?

No. Treat it as an identifier only and always authenticate with a username and password or certificates; brokers that bind IDs to credentials, as ConnectMQ does, add protection against impersonation.

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.