redis/redis-py · critical · AuthenticationError
Invalid Username or Password
Error message
Invalid Username or Password
What it means
Raised as AuthenticationError during the async connection handshake (on_connect) after the AUTH command's response is not the literal string 'OK'. The library sends AUTH with the configured username/password (retrying with just the password if the server rejects the arg count, indicating Redis < 6.0) and treats any non-OK reply as failed credentials. This is a hard failure: the connection is never returned to the pool healthy.
Solutions
- Verify the AUTH credentials directly with redis-cli -u '<url>' AUTH against the same endpoint.
- Confirm the password does not contain URL-special characters that need percent-encoding when passed via redis://user:pass@host; either percent-encode or pass username=/password= kwargs instead.
- Check the server's ACL LIST / CONFIG GET requirepass to confirm the user exists and the password matches.
- If the server is Redis < 6.0, pass only password= (no username) so the legacy single-arg AUTH path is taken.
- Rotate/refresh the credential source if using a token provider (e.g. EntraID) and re-create the client.
Example fix
// before
r = redis.asyncio.from_url('redis://default:pa$$w0rd@host:6379')
// after
r = redis.asyncio.Redis(host='host', username='default', password='pa$$w0rd') Defensive patterns
Strategy: try-catch
Validate before calling
import redis.asyncio as aioredis
async def probe_auth(url: str) -> bool:
r = aioredis.from_url(url, socket_connect_timeout=2)
try:
await r.ping()
return True
except aioredis.AuthenticationError:
return False
finally:
await r.aclose() Type guard
from redis.exceptions import AuthenticationError
def is_auth_error(exc: BaseException) -> bool:
return isinstance(exc, AuthenticationError) Try / catch
import redis.asyncio as aioredis
from redis.exceptions import AuthenticationError
try:
await client.ping()
except AuthenticationError:
# credentials wrong: do NOT retry blindly; refresh creds then recreate client
client = await rebuild_client_with_fresh_credentials() Prevention
- Validate credentials once at startup with a PING probe before entering the hot path.
- Pass username/password as kwargs (not URL-encoded) to avoid percent-encoding mistakes.
- For Redis < 6.0, pass password only (no username) so the legacy AUTH path is used.
- Use a secret manager / token provider so rotated creds are reloaded automatically.
When it happens
Trigger: Constructing redis.asyncio.Redis(... username=..., password=...) or from_url('redis://user:wrongpass@host') and issuing any command, which forces on_connect() -> AUTH. Also fires when a Redis 6+ ACL user lacks permission or the password is stale/wrong.
Common situations: Wrong password in env var/secret; rotated credentials not yet picked up; connecting with a username to a Redis < 6.0 server that uses legacy requirepass (the single-arg retry path); ACL user configured without +@all or with a denied password; copy-paste error including the URL-encoded percent in the literal password.
Related errors
- 'username' and 'password' cannot be passed along with…
- Error setting client name
- Invalid Database
- Bad response from PING health check
- Buffer is closed.
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/975cf63ef94737eb.
Report an issue: GitHub.
Appendix: source
Thrown at redis/asyncio/connection.py:993
) != int(self.protocol):
raise ConnectionError("Invalid RESP version")
# avoid checking health here -- PING will fail if we try
# to check the health prior to the AUTH
elif auth_args:
await self.send_command("AUTH", *auth_args, check_health=False)
try:
auth_response = await self.read_response()
except AuthenticationWrongNumberOfArgsError:
# a username and password were specified but the Redis
# server seems to be < 6.0.0 which expects a single password
# arg. retry auth with just the password.
# https://github.com/andymccurdy/redis-py/issues/1274
await self.send_command("AUTH", auth_args[-1], check_health=False)
auth_response = await self.read_response()
if str_if_bytes(auth_response) != "OK":
raise AuthenticationError("Invalid Username or Password")
# if resp version is specified, switch to it
elif check_protocol_version(self.protocol, 3):
if isinstance(self._parser, _AsyncRESP2Parser):
self.set_parser(_AsyncRESP3Parser)
# update cluster exception classes
self._parser.EXCEPTION_CLASSES = parser.EXCEPTION_CLASSES
self._parser.on_connect(self)
await self.send_command("HELLO", self.protocol, check_health=check_health)
response = await self.read_response()
# if response.get(b"proto") != self.protocol and response.get(
# "proto"
# ) != self.protocol:
# raise ConnectionError("Invalid RESP version")
# Activate maintenance notifications for this connection
# if enabled in the configuration
# This is a no-op if maintenance notifications are not enabledView on GitHub (pinned to 6a6b581b48)