InletDownload

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 arguments or … 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 NOPERM as usual. A command the script makes while it runs is refused with an ERR code 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 at EXEC with EXECABORT.

Common causes

  1. A read-only user tried to write. A user built from +@read can’t run SET, DEL, HSET and the like.
  2. The command is in a category the user lacks. -@dangerous also removes everyday-looking commands such as KEYS, INFO and CONFIG GET; ACL WHOAMI is only in @slow, so a user made of +@read +@connection can’t run it either.
  3. A key outside the user’s patterns. A user limited to ~app:* can’t touch session:1. One key out of bounds fails the whole command, so MGET app:1 session:1 is refused too.
  4. A key the user may only read. %R~cache:* allows GET cache:1 but not SET cache:1.
  5. A Pub/Sub channel the user lacks. Since Redis 7.0, new users get no channels unless you grant them (the acl-pubsub-default setting is resetchannels), so PUBLISH and SUBSCRIBE fail even for a user with +@all.
  6. 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 default user, 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

Sources