RabbitMQ Error Guide: 'PLAIN login refused: user does not exist' Authentication Failure
Fix RabbitMQ 'PLAIN login refused: user does not exist': missing users, vhost confusion, guest restrictions, auth backends, and rotated secrets.
- #rabbitmq
- #troubleshooting
- #errors
- #authentication
Exact Error Message
This error lives in the broker logs, not in your application stack trace. When a client tries to open an AMQP connection with a username the broker has never heard of, the node writes an authentication failure to /var/log/rabbitmq/rabbit@<node>.log:
2026-06-24 14:02:11.884 [info] <0.18643.0> accepting AMQP connection <0.18643.0> (10.42.7.19:51884 -> 10.42.7.4:5672)
2026-06-24 14:02:11.901 [error] <0.18643.0> Error on AMQP connection <0.18643.0> (10.42.7.19:51884 -> 10.42.7.4:5672, state: starting):
PLAIN login refused: user 'app' - invalid credentials
2026-06-24 14:02:11.902 [warning] <0.18643.0> closing AMQP connection <0.18643.0> (10.42.7.19:51884 -> 10.42.7.4:5672)
With debug logging enabled (or on newer 3.12+/4.x nodes), the auth backend spells out the precise reason on its own line:
2026-06-24 14:02:11.900 [debug] <0.18643.0> User 'app' authentication failed: user does not exist
The client side typically sees ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN, but the broker log is what tells you why: the user does not exist in the active authentication backend.
What the Error Means
RabbitMQ authenticates the PLAIN SASL mechanism by handing the supplied username and password to its configured auth_backends. The default backend is rabbit_auth_backend_internal, which looks the username up in the broker’s own Mnesia-backed user database.
“User does not exist” means the lookup returned nothing. The broker never even reached the password-comparison step. This is distinct from a wrong password: a wrong password produces a password mismatch, while a missing user fails earlier. RabbitMQ deliberately reports both as the generic client-facing invalid credentials so an attacker cannot distinguish “no such user” from “wrong password” by probing. You only see user does not exist in the broker’s own logs.
Crucially, users in RabbitMQ are global to a node/cluster, but permissions are scoped per virtual host. A user can exist yet have zero permissions on the vhost you are connecting to — that is a different failure (ACCESS_REFUSED ... vhost). The does not exist reason specifically means the username string itself was not found at all.
Common Causes
- The user was never created. A fresh broker, a rebuilt node, or a restored-from-empty Mnesia database simply has no
appuser. Definitions were never imported. - The user was deleted. Someone ran
rabbitmqctl delete_user app, or a definitions-import overwrote the user list with a set that omitted it. - Secret rotation gone wrong. A rotation pipeline updated the application’s password secret but recreated the user under a new name, or deleted the old user before the new credential propagated.
- Wrong username from config drift. The app reads
appfrom one secret store while the broker only knowsapp-prod. A typo, a staleRABBITMQ_DEFAULT_USER, or an environment-variable mismatch is enough. - Guest user restrictions. The default
guestuser exists but, for security, can only connect overlocalhost(loopback_users). A remoteguestconnection is refused; depending on version this can surface as an auth failure that looks like the user is unusable from off-box. - Wrong auth backend. The cluster was switched to
rabbit_auth_backend_ldapor an OAuth2 backend, and the internal user list is no longer consulted — so a locally-created user “does not exist” from the active backend’s point of view (and vice versa). - Vhost confusion masking the real issue. Operators sometimes create the user in the wrong context, or assume a user is missing when it actually lacks permissions on a specific vhost.
How to Reproduce the Error
The cleanest way to see this in a lab is to point a client at a username that does not exist. Spin up a broker and connect with a bogus user:
# Start a throwaway broker
docker run -d --name rmq -p 5672:5672 -p 15672:15672 rabbitmq:3.13-management
# Connect with the management HTTP API using a non-existent user
curl -u nosuchuser:whatever http://localhost:15672/api/overview
Then watch the broker log react:
docker logs rmq 2>&1 | grep -i "does not exist"
You will see the user does not exist reason recorded. Any AMQP client library (pika, amqplib, Spring AMQP) using nosuchuser will produce the same broker-side line while the client receives ACCESS_REFUSED.
Diagnostic Commands
Everything below is read-only — these commands inspect state without changing it. Run them on a cluster node.
Confirm whether the user actually exists:
# List every user known to the internal backend
rabbitmqctl list_users
Listing users ...
user tags
guest [administrator]
monitor [monitoring]
If app is absent from that list, the broker is correct: the user does not exist. Next, check vhosts and permissions to rule out the “exists but no permission” case:
# Show all virtual hosts
rabbitmqctl list_vhosts
# Show which users have permissions on which vhost
rabbitmqctl list_permissions -p /prod
# Show all permission tuples for one user (errors if user is missing)
rabbitmqctl list_user_permissions app
Listing permissions for user "app" ...
vhost configure write read
/prod .* .* .*
Test a credential pair without modifying anything — authenticate_user only verifies, it never creates or changes a user or password:
# Read-only credential check; prints "Success" or the failure reason
rabbitmqctl authenticate_user app 'THE_PASSWORD_FROM_YOUR_SECRET'
Inspect which auth backends are actually active and run the built-in diagnostics:
# Effective configuration, including auth_backends
rabbitmq-diagnostics environment | grep -A3 auth_backends
# General health and listener checks
rabbitmq-diagnostics status
rabbitmq-diagnostics check_running
Grep the logs for the exact reason and surrounding context:
# Find every "does not exist" auth rejection with timestamps
grep -i "login refused" /var/log/rabbitmq/rabbit@*.log
grep -i "user does not exist" /var/log/rabbitmq/rabbit@*.log
Step-by-Step Resolution
-
Confirm the username the client sends. Print the exact value the app uses (without leaking the password). Compare it byte-for-byte against
rabbitmqctl list_users. Watch for trailing whitespace, case differences (Appvsapp), and stale environment variables. -
Decide which backend is authoritative. Run
rabbitmq-diagnostics environment | grep auth_backends. If it showsrabbit_auth_backend_ldapor an OAuth2 backend, your fix belongs in that system — the internallist_usersis irrelevant, and you must create or sync the identity in LDAP/IdP instead. -
If the internal backend is active and the user is truly missing, create it. As a remediation step (not read-only), an operator runs
rabbitmqctl add_user app '<password>'followed byrabbitmqctl set_permissions -p /prod app ".*" ".*" ".*"and an appropriateset_user_tags. Pull the password from your secret manager rather than typing it; never echo it into a shared shell or log. -
If this is a
guestremote-connection problem, do not loosenloopback_usersin production. Instead create a dedicated application user with scoped permissions and point the client at it. -
If a rotation pipeline deleted the user, re-import your canonical definitions file or re-run the provisioning step. Make sure the rotation creates-then-switches (new user live before old credential is revoked) rather than delete-then-create.
-
Verify the fix with
authenticate_userusing the exact credential the app will use, then restart or reconnect the application. The broker log should stop emittinglogin refused. If you run an incident-response workflow, capture the before/afterlist_usersoutput as evidence.
Prevention and Best Practices
- Treat users and permissions as code. Maintain a
definitions.jsonand import it on bootstrap so a rebuilt node never comes up userless. - Never ship
guestto anything but local dev. Delete it or restrict it; provision per-service users with least-privilege permissions per vhost. - Make rotation idempotent and additive. Create the new credential, verify with
authenticate_user, switch the app, then revoke the old one — in that order. - Pin the auth backend explicitly in
rabbitmq.confso a config drift cannot silently swap which directory is authoritative. - Alert on the log line. Ship
login refusedanduser does not existto your log pipeline and page on a spike — it usually means a deploy or rotation broke.
Related Errors
ACCESS_REFUSED - Login was refused using authentication mechanism PLAINis the client-side counterpart. It appears for both missing users and wrong passwords; the broker log disambiguates. See our dedicated ACCESS_REFUSED guide.ACCESS_REFUSED - access to vhost '/prod' refused for user 'app'means the user exists but has no permission on that vhost — a permissions problem, not a missing-user problem.PRECONDITION_FAILEDis unrelated to auth; it fires on mismatched queue/exchange declarations (e.g., redeclaring a durable queue as non-durable).not_found - no vhost '/prod'indicates the virtual host itself is missing, which can masquerade as an auth failure during connection setup.
Frequently Asked Questions
Why does the client only see “invalid credentials” when the real reason is “user does not exist”? This is intentional. Exposing whether a username exists would help attackers enumerate valid accounts, so RabbitMQ returns a generic message to clients and logs the specific reason only on the broker.
My user shows up in rabbitmqctl list_users but I still get refused. Why? The user exists globally, but permissions are per-vhost. Check rabbitmqctl list_user_permissions <user> — you are likely hitting an ACCESS_REFUSED ... vhost error, not a missing-user error.
Does authenticate_user change the password or lock the account? No. It is purely a read-only verification that returns success or the failure reason. It never modifies the user, password, or any state.
We switched to LDAP and now every user “does not exist.” What happened? The active backend determines where lookups go. With LDAP active, internally-created users are invisible. Provision identities in your directory, or list the internal backend as a fallback in auth_backends.
Can the default guest user connect from another host? Not by default. guest is restricted to loopback connections. For remote access, create a dedicated user instead of relaxing that restriction. For more RabbitMQ fixes, browse the RabbitMQ category.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.