Redis error NOPERM
NOPERM User reader has no permissions to run the 'set' command
You’re signed in as an ACL user that isn’t allowed to run that command, or to use that key or channel, so the server refused it without running it. Check which user you are and what it may do, then sign in as another user or change its rules.
NOPERM User reader has no permissions to run the 'set' command
Tested on Redis 8.10.2 and Valkey 8.1.10 · Updated 9 October 2026
What it means
Since Redis 6, every connection runs as an ACL user, and each user has rules: which commands it may
run (+@read, -@dangerous, +get), which keys it may use (~app:*, or %R~cache:* for read
only), and which Pub/Sub channels (&news:*). The server checks each command against those rules
before running it. NOPERM means a check failed, and nothing ran.
It comes in three forms, one for each kind of rule:
NOPERM User reader has no permissions to run the 'set' command
NOPERM No permissions to access a key
NOPERM No permissions to access a channel
A subcommand shows with a bar: 'config|get', 'acl|whoami'. The key and channel forms don’t say
which key or channel; ACL LOG and ACL DRYRUN do (below). Redis 8.10.2 and Valkey 8.1.10 word all
three the same way. Older versions differ (from Redis’s source):
- Redis 7.0:
NOPERM this user has no permissions to run the 'set' command, and… to access one of the keys used as argumentsor… one of the channels used as arguments. - Redis 6.x: as 7.0, but the first ends
the 'set' command or its subcommand.
Two related cases:
- Inside a Lua script, a key passed as a key argument is checked before the script starts, and
refused with
NOPERMas usual. A command the script makes while it runs is refused with anERRcode instead:ERR ACL failure in script: No permissions to access a key script: <sha>, on @user_script:1. - Inside
MULTI, the command is refused when it’s queued, and the whole transaction then fails atEXECwith EXECABORT.
Common causes
- A read-only user tried to write. A user built from
+@readcan’t runSET,DEL,HSETand the like. - The command is in a category the user lacks.
-@dangerousalso removes everyday-looking commands such asKEYS,INFOandCONFIG GET;ACL WHOAMIis only in@slow, so a user made of+@read +@connectioncan’t run it either. - A key outside the user’s patterns. A user limited to
~app:*can’t touchsession:1. One key out of bounds fails the whole command, soMGET app:1 session:1is refused too. - A key the user may only read.
%R~cache:*allowsGET cache:1but notSET cache:1. - A Pub/Sub channel the user lacks. Since Redis 7.0, new users get no channels unless you grant
them (the
acl-pubsub-defaultsetting isresetchannels), soPUBLISHandSUBSCRIBEfail even for a user with+@all. - You’re signed in as a different user than you think: the connection string names another
user, or no user at all, so you’re the
defaultuser, whose rules on a shared or hosted server may be narrow.
How to fix it
Check who you are
ACL WHOAMI
If that’s refused too, CLIENT INFO (allowed to any user with @connection) shows the user in its
user= field.
Ask the server what a user may do
Signed in as an administrator:
ACL GETUSER <user>
ACL DRYRUN <user> SET <key> <value>
ACL GETUSER lists the user’s command rules, key patterns and channels. ACL DRYRUN (Redis 7.0
and later, and Valkey) checks a command without running it: it replies OK if the user may run it,
or says exactly why not, naming the key or channel:
"User app has no permissions to access the 'session:1' key"
ACL CAT <category> lists the commands in a category, such as ACL CAT dangerous.
Read the ACL log
ACL LOG 10
Each entry has a reason (command, key, channel or auth), the object that was refused
(the command, key or channel name), the username, a context (toplevel, multi, lua or
module) and the client’s address. ACL LOG RESET clears it. Redis’s documentation lists ACL LOG
as not supported on Redis Cloud.
Sign in as the right user
If your server has separate users, say a read-only one for reporting and another for the
application, sign in as the one with the rights you need: AUTH <user> <password>, or the user name
in your URL (redis://<user>:<password>@<host>:6379).
Change the user’s rules
As an administrator, ACL SETUSER adds rules to what the user already has:
ACL SETUSER reader +set
ACL SETUSER app ~session:*
ACL SETUSER app &chat
Then save them where the users are defined (ACL SAVE for an ACL file, or the user line in
redis.conf), or they’re lost on restart. On a hosted Redis, users and their rules are usually managed
in the provider’s console.
Reproduce it
Redis 8.10.2, redis-cli 8.10.2, signed in as reader, a user with
-@all +@read +@connection -@dangerous and every key (~*), in database 15:
SET seo:auth:x 1
(error) NOPERM User reader has no permissions to run the 'set' command
GET seo:auth:x
(nil)
KEYS seo:auth:*
(error) NOPERM User reader has no permissions to run the 'keys' command
CONFIG GET maxmemory
(error) NOPERM User reader has no permissions to run the 'config|get' command
ACL WHOAMI
(error) NOPERM User reader has no permissions to run the 'acl|whoami' command
DEL, INFO, PUBLISH, EVAL and ACL LOG were refused the same way, each named in the message.
CLIENT INFO worked and included user=reader. Signed in as an administrator:
ACL WHOAMI
"inlet"
ACL DRYRUN reader SET seo:auth:x 1
"User reader has no permissions to run the 'set' command"
ACL DRYRUN reader GET seo:auth:x
OK
Valkey 8.1.10 gave every reply word for word.
The key and channel forms need a user with limited keys, so they ran on temporary Redis 8.10.2 and
Valkey 8.1.10 servers, with a user app created as ACL SETUSER app on >… ~app:* &news:* +@all:
SET app:1 x
OK
SET session:1 x
(error) NOPERM No permissions to access a key
MGET app:1 session:1
(error) NOPERM No permissions to access a key
PUBLISH chat hi
(error) NOPERM No permissions to access a channel
PUBLISH news:today hi
(integer) 0
ACL DRYRUN app PUBLISH chat hi replied "User app has no permissions to access the 'chat' channel".
After a refused GET session:9, ACL LOG 1 began:
1) 1) "count"
2) (integer) 1
3) "reason"
4) "key"
5) "context"
6) "toplevel"
7) "object"
8) "session:9"
9) "username"
10) "app"
…
A user with %R~cache:* got (nil) for GET cache:1 and NOPERM No permissions to access a key
for SET cache:1 x. A script given session:1 as its key argument
(EVAL "return redis.call('SET', KEYS[1], 'x')" 1 session:1) was refused with the same NOPERM
before it started. With the key named only inside the script, and then in a transaction:
(error) ERR ACL failure in script: No permissions to access a key script: 631a3c3d2b3b3b71fc3127fff4029986c2ba7d2a, on @user_script:1.
MULTI
OK
SET app:2 y
QUEUED
SET session:2 y
(error) NOPERM No permissions to access a key
EXEC
(error) EXECABORT Transaction discarded because of previous errors.
Both servers gave the same text in every case.
In Inlet
Inlet signs in with an ACL user and password, or a password alone. It doesn’t manage ACL users yet,
but query tabs take redis-cli commands, so you can run ACL WHOAMI, ACL GETUSER and ACL DRYRUN
there, as a user allowed to. When the server refuses a command, Inlet shows the message after the
NOPERM code and links to this page. Separately, connections tagged production are read-only:
Inlet refuses write and admin commands itself, before they’re sent, so that refusal isn’t a
NOPERM from the server.
Related
- WRONGPASS invalid username-password pair or user is disabled.
- NOAUTH Authentication required.
- EXECABORT Transaction discarded because of previous errors.
- WRONGTYPE Operation against a key holding the wrong kind of value
- Redis connection string: redis:// and rediss:// URLs explained
- Connect to Redis Cloud from your Mac
- Connect to Amazon ElastiCache for Redis OSS or Valkey from your Mac
- Connect to Valkey from your Mac
Sources
- redis.io/docs/latest/operate/oss_and_stack/management/security/acl/
- redis.io/docs/latest/commands/acl-dryrun/
- redis.io/docs/latest/commands/acl-log/
- redis.io/docs/latest/commands/acl-whoami/
- redis.io/docs/latest/commands/acl-getuser/
- valkey.io/topics/acl/
- github.com/redis/redis/blob/7.2/src/acl.c
- github.com/redis/redis/blob/7.0/src/server.c
- github.com/redis/redis/blob/6.2/src/server.c
- github.com/redis/redis/blob/unstable/redis.conf