nats-io/nats-server · error
mqtt authentication token not compatible with presence of us
Error message
mqtt authentication token not compatible with presence of users/nkeys
What it means
MQTT inbound authentication can be configured either via a single MQTT-level token (Options.MQTT.Token) or via the server's users/nkeys mechanism, but not both at once. The NATS server rejects Options during validation (server/mqtt.go:721) because combining them creates ambiguous credential precedence for MQTT clients. It is a configuration-time error from ProcessOptions/NewServer, not a runtime client failure.
Source
Thrown at server/mqtt.go:231
)
var (
mqttPingResponse = []byte{mqttPacketPingResp, 0x0}
mqttProtoName = []byte("MQTT")
mqttOldProtoName = []byte("MQIsdp")
mqttSessJailDur = mqttSessFlappingJailDur
mqttFlapCleanItvl = mqttSessFlappingCleanupInterval
mqttRetainedCacheTTL = mqttDefaultRetainedCacheTTL
)
var (
errMQTTNotWebsocketPort = errors.New("MQTT clients over websocket must connect to the Websocket port, not the MQTT port")
errMQTTTopicFilterCannotBeEmpty = errors.New("topic filter cannot be empty")
errMQTTMalformedVarInt = errors.New("malformed variable int")
errMQTTSecondConnectPacket = errors.New("received a second CONNECT packet")
errMQTTServerNameMustBeSet = errors.New("mqtt requires server name to be explicitly set")
errMQTTUserMixWithUsersNKeys = errors.New("mqtt authentication username not compatible with presence of users/nkeys")
errMQTTTokenMixWIthUsersNKeys = errors.New("mqtt authentication token not compatible with presence of users/nkeys")
errMQTTAckWaitMustBePositive = errors.New("ack wait must be a positive value")
errMQTTJSAPITimeoutMustBePositive = errors.New("JS API timeout must be a positive value")
errMQTTStandaloneNeedsJetStream = errors.New("mqtt requires JetStream to be enabled if running in standalone mode")
errMQTTConnFlagReserved = errors.New("connect flags reserved bit not set to 0")
errMQTTWillAndRetainFlag = errors.New("if Will flag is set to 0, Will Retain flag must be 0 too")
errMQTTPasswordFlagAndNoUser = errors.New("password flag set but username flag is not")
errMQTTCIDEmptyNeedsCleanFlag = errors.New("when client ID is empty, clean session flag must be set to 1")
errMQTTEmptyWillTopic = errors.New("empty Will topic not allowed")
errMQTTEmptyUsername = errors.New("empty user name not allowed")
errMQTTTopicIsEmpty = errors.New("topic cannot be empty")
errMQTTPacketIdentifierIsZero = errors.New("packet identifier cannot be 0")
errMQTTUnsupportedCharacters = errors.New("character not supported for MQTT topics")
errMQTTInvalidSession = errors.New("invalid MQTT session")
errMQTTInvalidRetainFlags = errors.New("invalid retained message flags")
errMQTTInvalidRetainedMessage = errors.New("invalid retained message")
errMQTTSessionCollision = errors.New("stored session does not match client ID")
errMQTTInvalidPublishLength = errors.New("invalid publish message, variable header exceeds remaining length")
errMQTTAckPipelineStopped = errors.New("QoS1 PUBACK pipeline has shut down while admitting a message, " +View on GitHub (pinned to 3a66a489d2)
Solutions
- Remove the MQTT.Token field from your Options/config and rely on the per-user credentials for MQTT clients.
- Alternatively remove the users/nkeys entries so the MQTT-level token is the sole authentication mechanism.
- If using a config file, restart after editing and check that only one MQTT auth mechanism is declared.
Example fix
// before
o := &server.Options{MQTT: server.MQTTOpts{Token: "mytoken"}}
o.Users = []*server.User{{Username: "u", Password: "p"}}
// after
o := &server.Options{MQTT: server.MQTTOpts{}}
o.Users = []*server.User{{Username: "u", Password: "p"}} Defensive patterns
Strategy: validation
Validate before calling
if o.MQTT.Token != "" && (len(o.Users) > 0 || o.Nkeys != nil) {
return fmt.Errorf("remove MQTT.Token: it conflicts with users/nkeys auth")
} Try / catch
if _, err := server.NewServer(opts); err != nil {
if strings.Contains(err.Error(), "token not compatible") {
// drop MQTT.Token and rebuild options
}
} Prevention
- Keep a single auth mechanism per listener; audit config files after merging snippets.
- Add a unit test asserting NewServer succeeds with your production Options.
- Validate Options in CI before deploying configs.
When it happens
Trigger: Setting opts.MQTT.Token to a non-empty string while the Options also define users (opts.Users), an nkey, or an account setup where users/nkeys authentication is present; returned by option validation before the server starts.
Common situations: Operators copy an MQTT snippet that sets MQTT.Token into an existing NATS config file that already declares a users block, or migrate from static token auth to users/nkeys without removing the old MQTT.Token entry.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- mqtt authentication username not compatible with presence of
- ack wait must be a positive value
- JS API timeout must be a positive value
- mqtt requires JetStream to be enabled if running in standalo
- password flag set but username flag is not
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/3803a9be2b999afd.
Report an issue: GitHub.