{"record":{"id":"ce8425589e2765b6","repo":"nats-io/nats-server","slug":"stored-session-does-not-match-client-id","errorCode":null,"errorMessage":"stored session does not match client ID","messagePattern":"stored session does not match client ID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/mqtt.go","lineNumber":247,"sourceCode":"\terrMQTTServerNameMustBeSet        = errors.New(\"mqtt requires server name to be explicitly set\")\n\terrMQTTUserMixWithUsersNKeys      = errors.New(\"mqtt authentication username not compatible with presence of users/nkeys\")\n\terrMQTTTokenMixWIthUsersNKeys     = errors.New(\"mqtt authentication token not compatible with presence of users/nkeys\")\n\terrMQTTAckWaitMustBePositive      = errors.New(\"ack wait must be a positive value\")\n\terrMQTTJSAPITimeoutMustBePositive = errors.New(\"JS API timeout must be a positive value\")\n\terrMQTTStandaloneNeedsJetStream   = errors.New(\"mqtt requires JetStream to be enabled if running in standalone mode\")\n\terrMQTTConnFlagReserved           = errors.New(\"connect flags reserved bit not set to 0\")\n\terrMQTTWillAndRetainFlag          = errors.New(\"if Will flag is set to 0, Will Retain flag must be 0 too\")\n\terrMQTTPasswordFlagAndNoUser      = errors.New(\"password flag set but username flag is not\")\n\terrMQTTCIDEmptyNeedsCleanFlag     = errors.New(\"when client ID is empty, clean session flag must be set to 1\")\n\terrMQTTEmptyWillTopic             = errors.New(\"empty Will topic not allowed\")\n\terrMQTTEmptyUsername              = errors.New(\"empty user name not allowed\")\n\terrMQTTTopicIsEmpty               = errors.New(\"topic cannot be empty\")\n\terrMQTTPacketIdentifierIsZero     = errors.New(\"packet identifier cannot be 0\")\n\terrMQTTUnsupportedCharacters      = errors.New(\"character not supported for MQTT topics\")\n\terrMQTTInvalidSession             = errors.New(\"invalid MQTT session\")\n\terrMQTTInvalidRetainFlags         = errors.New(\"invalid retained message flags\")\n\terrMQTTInvalidRetainedMessage     = errors.New(\"invalid retained message\")\n\terrMQTTSessionCollision           = errors.New(\"stored session does not match client ID\")\n\terrMQTTInvalidPublishLength       = errors.New(\"invalid publish message, variable header exceeds remaining length\")\n\terrMQTTAckPipelineStopped         = errors.New(\"QoS1 PUBACK pipeline has shut down while admitting a message, \" +\n\t\t\"abandoning the wait for its JetStream ack; failing the connection, \" +\n\t\t\"the client will re-send unacknowledged PUBLISH packets on reconnect\")\n)\n\ntype srvMQTT struct {\n\tlistener     net.Listener\n\tlistenerErr  error\n\tauthOverride bool\n\tsessmgr      mqttSessionManager\n}\n\ntype mqttSessionManager struct {\n\tmu       sync.RWMutex\n\tsessions map[string]*mqttAccountSessionManager // key is account name\n}\n","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/mqtt.go#L229-L265","documentation":"This sentinel error (errMQTTSessionCollision) is returned by the NATS server's MQTT layer when a persisted MQTT session is restored from storage but its recorded client ID does not match the client ID of the connection attempting to resume it. The MQTT session is keyed by the client identifier, so a mismatch means the stored session belongs to a different logical client and cannot be safely reused; the code at server/mqtt.go:3177 compares ps.ID against clientID and fails the restore. Returning it prevents cross-client message/state leakage.","triggerScenarios":"A client connects with clean session=false and a client ID whose stored session record maps to a different client ID (e.g. the session store was reused across servers, storage keys collided, or a store migration reassigned session keys), causing the ps.ID != clientID check in the session restore path to fail.","commonSituations":"Sharing one JetStream/stream bucket for MQTT sessions between multiple NATS servers without namespacing; manually editing or migrating persistent session state; resuming sessions after restoring a snapshot where session keys were regenerated; clients reusing a client ID after a server-side session store was rebuilt.","solutions":["Verify each MQTT client uses a unique, stable client ID and that the session store is keyed by that same client ID","Check that the session persistence store is not shared or contaminated between servers/environments; use per-server or per-cluster namespaced storage","If stale state is the cause, clear the stored session for that client ID (or have the client reconnect with Clean Session=true to purge it) and reconnect","Upgrade/patch to a server version where the session store keying matches your deployment topology"],"exampleFix":"// before: reusing a shared store with colliding keys\nclient.Connect(mqtt.NewClientOptions().SetClientID(\"device-1\").SetCleanSession(false))\n// after: unique client ID per device + clean start after storage collision\nclient.Connect(mqtt.NewClientOptions().SetClientID(\"device-1-\" + deviceUUID).SetCleanSession(false))","handlingStrategy":"validation","validationCode":"// before connecting with CleanSession=false, ensure the client ID is unique per device\nif clientID == \"\" || !strings.HasPrefix(clientID, deviceUUIDPrefix) {\n    clientID = deviceUUIDPrefix + deviceUUID\n}\n// on collision, fall back to a clean session\nopts := mqtt.NewClientOptions().SetClientID(clientID).SetCleanSession(firstAttempt == false)","typeGuard":null,"tryCatchPattern":"// Go: treat the connack failure as a session-store issue\nerr := nc.Connect()\nif err != nil && strings.Contains(err.Error(), \"stored session does not match client ID\") {\n    // purge stored session for this client ID, then reconnect with Clean Session\n    purgeStoredSession(clientID)\n    reconnect(cleanSession = true)\n}","preventionTips":["Derive client IDs from immutable device identity, never from hostnames or shared defaults","Do not share MQTT session stores between unrelated servers/clusters","After restoring snapshots or migrating storage, rebuild or verify session key->client ID mappings"],"tags":["mqtt","session","nats-server","storage"],"backgroundTag":"mqtt-session-collision","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}