You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
RedisConnectionSettings has password but no username, so a client built by redis-client-kit always authenticates as the default user. That rules out Redis ACL users (Redis 6+), which are the standard way to share one Redis between several applications safely.
Our case: several products share one Redis. Each product should get its own ACL user restricted to its key prefix and channels, for example:
With only password, every product has to log in as default with the shared password. Then any of them can read, overwrite or FLUSHDB the others' keys.
redis-py already supports this: Redis(...), ConnectionPool(...), the asyncio client and RedisCluster(...) all accept username= next to password=. Only the settings and the kwargs builder are missing.
What we would like to see
RedisConnectionSettings.username: str | None = None (description: "Redis ACL user name (optional; default when unset)"). It is set via the usual nested env var, e.g. REDIS__CONNECTION__USERNAME.
build_base_redis_kwargs passes "username": settings.connection.username next to "password". Both the sync and the asyncio paths and cluster mode get it.
Logging and masking stay as they are: password is still masked; username is not secret, so it may appear in masked kwargs or connection info.
Tests:
kwargs contain the username when it is set, and None or no key when it is not (same behaviour as today for the default user);
the settings read REDIS__CONNECTION__USERNAME from the environment;
an integration test, if the suite has a real Redis: ACL SETUSER a user limited to ~app:*, connect with username/password, then SET app:x succeeds and GET other:x raises NoPermissionError (NOPERM).
Docs (README / settings reference) and a CHANGELOG entry. This is additive and backwards compatible, so a patch or minor release fits (0.3.1 or 0.4.0).
Out of scope
Credential providers and rotating passwords. A plain username + password pair is enough.
Taking this one. I reproduced it on master first against redis:7-alpine: with an ACL user's password in connection.password, RESP2 fails with "AUTH called without any password configured for the default user", and RESP3 is worse — redis-py sends HELLO 3 AUTH default <password>, a nopass default user accepts it, and the client gets full access, FLUSHDB included.
Plan:
RedisConnectionSettings.username: str | None = None, described as in the issue.
build_base_redis_kwargs passes username next to password, so single, cluster, sync and asyncio all get it. redis-py's RedisCluster takes it through **kwargs (it is in REDIS_ALLOWED_KEYS).
One deviation from the letter of point 2: the kwargs builder reads it as getattr(settings.connection, "username", None) and RedisConnectionProtocol does not gain a required member, only a docstring line. The configuration guide shows hand-written settings objects implementing the protocols, and the docs promise that every attribute the protocols name is read; adding username there would make those objects fail with AttributeError (and mypy) on upgrade, which is not the backwards-compatible change this asks for.
Masking stays as it is; a test pins that username survives mask_redis_kwargs.
Tests: kwargs with and without a username, a protocol object with no username attribute, cluster kwargs on both sides, settings read from REDIS__CONNECTION__USERNAME, and integration tests on a real Redis: an ACL user limited to ~app:* can SET app:x, gets NoPermissionError on GET other:x and on FLUSHDB, and passes the kit's own health check and write probe.
Docs: the configuration guide gets an "ACL users" section with a rule that works with the kit. The rule in the issue is not enough for it: the health check needs +ping, client_name needs +client|setname, db != 0 needs +select, and +@write still allows FLUSHDB until -@dangerous takes it away. I checked each of those on a live server. docs/agents.md gets the new field.
CHANGELOG: release-please writes it from the feat: squash title, so no hand edit; this lands as 0.4.0.
PR is up: #49. It follows the plan above. One thing to decide when you review: username is read with getattr and is not a member of RedisConnectionProtocol, so hand-written settings objects keep working. If you would rather have it in the protocol and ship this as a breaking change, it's two lines. CI is green, including the ACL integration tests on RESP2 and RESP3.
Activity
AlexeyShalaev commentedon Oct 9, 2026
Taking this one. I reproduced it on master first against
redis:7-alpine: with an ACL user's password inconnection.password, RESP2 fails with "AUTH called without any password configured for the default user", and RESP3 is worse — redis-py sendsHELLO 3 AUTH default <password>, anopassdefault user accepts it, and the client gets full access,FLUSHDBincluded.Plan:
RedisConnectionSettings.username: str | None = None, described as in the issue.build_base_redis_kwargspassesusernamenext topassword, so single, cluster, sync and asyncio all get it. redis-py'sRedisClustertakes it through**kwargs(it is inREDIS_ALLOWED_KEYS).getattr(settings.connection, "username", None)andRedisConnectionProtocoldoes not gain a required member, only a docstring line. The configuration guide shows hand-written settings objects implementing the protocols, and the docs promise that every attribute the protocols name is read; addingusernamethere would make those objects fail withAttributeError(and mypy) on upgrade, which is not the backwards-compatible change this asks for.usernamesurvivesmask_redis_kwargs.usernameattribute, cluster kwargs on both sides, settings read fromREDIS__CONNECTION__USERNAME, and integration tests on a real Redis: an ACL user limited to~app:*canSET app:x, getsNoPermissionErroronGET other:xand onFLUSHDB, and passes the kit's own health check and write probe.+ping,client_nameneeds+client|setname,db != 0needs+select, and+@writestill allowsFLUSHDBuntil-@dangeroustakes it away. I checked each of those on a live server.docs/agents.mdgets the new field.feat:squash title, so no hand edit; this lands as 0.4.0.AlexeyShalaev commentedon Oct 9, 2026
PR is up: #49. It follows the plan above. One thing to decide when you review:
usernameis read withgetattrand is not a member ofRedisConnectionProtocol, so hand-written settings objects keep working. If you would rather have it in the protocol and ship this as a breaking change, it's two lines. CI is green, including the ACL integration tests on RESP2 and RESP3.feat!: log in as a Redis ACL user with connection.username (#49)