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

  1. Remove the MQTT.Token field from your Options/config and rely on the per-user credentials for MQTT clients.
  2. Alternatively remove the users/nkeys entries so the MQTT-level token is the sole authentication mechanism.
  3. 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

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

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/3803a9be2b999afd. Report an issue: GitHub.