Fix Redis "NOAUTH Authentication Required" and WRONGPASS in Django
Fix Redis NOAUTH Authentication required and WRONGPASS invalid username-password pair errors in Django and Celery: put the password in the Redis URL correctly, URL-encode special characters, use ACL usernames, and keep cache and broker settings in sync.
Problem statement
After enabling a Redis password, moving to a managed Redis, or rotating credentials, Django or Celery fails with one of these:
redis.exceptions.AuthenticationError: Authentication required.
NOAUTH Authentication required.
WRONGPASS invalid username-password pair or user is disabled.
NOAUTH means the client sent commands without authenticating at all; the password never reached Redis. WRONGPASS means it authenticated with the wrong username or password. Both usually come from how the Redis URL is written, or from one component (cache, Celery broker, Celery results, Channels) still using the old URL.
- Put credentials in the URL:
redis://:PASSWORD@host:6379/0(note the colon before the password) orredis://USER:PASSWORD@host:6379/0for ACL users. - URL-encode special characters in the password (
@→%40,/→%2F,#→%23). - Use
rediss://when the provider requires TLS. - Update every client:
CACHES,CELERY_BROKER_URL,CELERY_RESULT_BACKEND,CHANNEL_LAYERS, and anydjango-rqqueues. - Test with
redis-cli -u "$REDIS_URL" PINGfrom the app server.
Step-by-step solution
1. Test the URL directly
redis-cli -u "$REDIS_URL" PING
PONG means the URL works. NOAUTH or WRONGPASS here means the URL itself is wrong, independent of Django.
2. Write the URL correctly
The password goes in the user-info part of the URL. Without an ACL username, keep the leading colon:
# password only (default user)
redis://:s3cret@redis.internal:6379/0
# ACL username and password (Redis 6+)
redis://app:s3cret@redis.internal:6379/0
# TLS
rediss://app:s3cret@redis.example.com:6380/0
redis://s3cret@host without the colon is parsed as a username with no password, and Redis replies NOAUTH.
3. Encode special characters
Generated passwords often include characters that break URL parsing. Encode the password once:
python3 -c "import urllib.parse, getpass; print(urllib.parse.quote(getpass.getpass(), safe=''))"
Alternatively, pass the password separately. django-redis accepts "OPTIONS": {"PASSWORD": os.environ["REDIS_PASSWORD"]}, and Celery accepts broker_transport_options only for some transports, so the URL form is the most portable.
4. Update every component
A project can have four or five separate Redis clients:
REDIS_URL = os.environ["REDIS_URL"]
CACHES = {"default": {"BACKEND": "django_redis.cache.RedisCache", "LOCATION": f"{REDIS_URL}/1"}}
CELERY_BROKER_URL = f"{REDIS_URL}/0"
CELERY_RESULT_BACKEND = f"{REDIS_URL}/2"
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {"hosts": [f"{REDIS_URL}/3"]},
}
}
Building all of them from one variable means a credential change updates them together. Note that this example assumes REDIS_URL has no database number at the end.
5. ACL users and permissions
With Redis 6+ ACLs, a user can authenticate but lack permission for some commands, which gives NOPERM instead. Celery needs commands such as BRPOP, MULTI, EVAL, and pub/sub; a cache needs GET, SET, DEL, SCAN, and others. A practical ACL for an app user:
ACL SETUSER app on >s3cret ~* &* +@all -@dangerous
Restrict key patterns (~app:*) only if every component uses a prefix.
Explanation
Redis checks authentication per connection. When requirepass or ACLs are enabled, a client must send AUTH before other commands, and redis-py does that automatically when the URL contains credentials. If the URL parser finds no password, redis-py skips AUTH, and the first real command returns NOAUTH. Because Django, Celery, and Channels each create their own clients from their own settings, it is common for one to work and another to fail.
Edge cases / notes
- Credential rotation. Managed services such as ElastiCache allow two auth tokens during rotation. Deploy the new token to every component before removing the old one.
- Heroku-style URLs. Some providers rotate credentials and update
REDIS_URLautomatically; settings that copy the value into a file at build time miss the change. - Flower and monitoring. Separate tools need the new URL too, or they show workers as offline.
Next steps
- If the connection never opens, see Fix Redis Connection Refused in Django.
- TLS problems are covered in Fix Redis SSL Certificate Verify Failed.
- Harden the setup with the Django Redis Production Checklist.
FAQ
Why do I need a colon before the password?
In a URL, the part before the colon is the username. redis://:password@host sets an empty username and a password; without the colon, the password is read as a username.
Can I keep the password out of the URL?
django-redis accepts a separate PASSWORD option. Celery and Channels are easiest with the URL form, built from an environment variable.
What is the difference between NOAUTH and WRONGPASS?
NOAUTH means no credentials were sent. WRONGPASS means credentials were sent and rejected.
Should my Redis have a password if it is on a private network?
Yes. Private networks still contain other services that can be compromised, and managed providers often require it.