Fix Redis NOPERM Error: User Has No Permissions to Run Commands (ACL)

intermediate๐Ÿ”ด Redis2026-05-05| Redis 6.0+ on Linux/macOS/Windows (WSL), any client (redis-cli, Jedis, ioredis, redis-py)

Error Message

NOPERM this user has no permissions to run the 'get' command
#redis#acl#security#noperm

The Error

You run a command against Redis and get slapped with this:

127.0.0.1:6379> GET mykey
(error) NOPERM this user has no permissions to run the 'get' command

Or from application logs:

ReplyError: NOPERM this user has no permissions to run the 'get' command

This is Redis ACL (Access Control List) doing its job โ€” a feature introduced in Redis 6.0 (released April 2020). The user your client authenticated as doesn't have permission to run that command, or can't access that key pattern.

Why This Happens

Every connection in Redis authenticates as some user โ€” either a named one you set up, or the implicit default user if no credentials are sent. Each user has ACL rules that control which commands they can run, which key patterns they can touch, and which pub/sub channels they can use. Hit a restriction? Redis fires back NOPERM.

The usual culprits:

  • The default user was locked down via aclfile or ACL SETUSER
  • A dedicated app user was created but got only write permissions โ€” or only read, depending on who configured it
  • The user has command access but the key doesn't match their allowed pattern (e.g., only cache:* keys are permitted)
  • A recent security hardening sweep stripped broad command access from existing users

Step 1: Check What User You're Connecting As

Start here. Confirm which user is active in your session:

127.0.0.1:6379> ACL WHOAMI
"appuser"

Seeing default? Your client isn't sending credentials โ€” it's connecting unauthenticated. Seeing a named user? That's whose ACL rules are blocking you.

Step 2: Inspect the User's ACL Rules

127.0.0.1:6379> ACL GETUSER appuser
 1) "flags"
 2) 1) "on"
 3) "passwords"
 4) 1) "...(hashed)"
 5) "commands"
 6) "+set -get"
 7) "keys"
 8) "cache:*"
 9) "channels"
10) "*"

Focus on two fields. commands shows what's allowed โ€” in the example above, +set -get means SET is permitted but GET is explicitly denied. Then check keys: even with a command allowed, the user might be locked to specific key patterns like cache:*.

To see all users at once:

127.0.0.1:6379> ACL LIST
1) "user default on nopass ~* &* +@all"
2) "user appuser on #abc123... ~cache:* +set -get"

Step 3: Grant the Missing Permission

Connect as an admin user (one with +@all or at least +acl), then use ACL SETUSER to fix the rules.

Allow a specific command

ACL SETUSER appuser +get

Allow a command category (e.g., all read commands)

ACL SETUSER appuser +@read

Allow all commands (only for trusted internal services)

ACL SETUSER appuser +@all

Allow specific key patterns

ACL SETUSER appuser ~cache:* ~session:*

Full example โ€” rebuild a read-only user from scratch

ACL SETUSER readonly_app on >SecurePass123 ~* +@read

This creates (or overwrites) a user that:

  • Is enabled (on)
  • Has password SecurePass123
  • Can access all key patterns (~*)
  • Can run all read commands (+@read) โ€” GET, MGET, LRANGE, SMEMBERS, HGET, and more

Step 4: Persist ACL Changes

ACL SETUSER only updates in-memory state. Restart Redis and everything reverts. Two ways to make changes stick:

Option A: Use an ACL file (recommended)

In your redis.conf:

aclfile /etc/redis/users.acl

Then flush the current rules to disk:

127.0.0.1:6379> ACL SAVE

Redis writes all user rules to that file and reloads from it on restart.

Option B: Inline in redis.conf

Drop user rules directly into your config:

user appuser on >SecurePass123 ~cache:* +@read +set

Restart Redis after saving the file.

Step 5: Verify the Fix

Pull the user's rules again and confirm the commands look right:

127.0.0.1:6379> ACL GETUSER appuser
...
 5) "commands"
 6) "+@read +set"

Then run the command that was failing:

127.0.0.1:6379> AUTH appuser SecurePass123
OK
127.0.0.1:6379> GET mykey
"hello"

Gone. You can also check the ACL log to review recent denials โ€” useful if you're not sure what else might be blocked:

127.0.0.1:6379> ACL LOG
1) 1) "count"
   2) (integer) 3
   3) "reason"
   4) "command"
   5) "context"
   6) "toplevel"
   7) "object"
   8) "get"
   9) "username"
  10) "appuser"
  ...

Clear it once you're done troubleshooting:

ACL LOG RESET

Tips

Command categories save a lot of typing

Instead of listing individual commands, Redis lets you grant entire categories at once:

  • +@read โ€” GET, MGET, LRANGE, SMEMBERS, HGET, etc.
  • +@write โ€” SET, DEL, LPUSH, SADD, HSET, etc.
  • +@string โ€” all string commands
  • +@hash โ€” all hash commands
  • +@dangerous โ€” FLUSHDB, CONFIG, DEBUG, etc. (keep this locked down)

List all available categories:

ACL CAT

See exactly which commands are in one:

ACL CAT read

Least privilege โ€” actually follow it

Don't hand out +@all just to make the error go away. It's tempting, but it defeats the whole point of ACL. A background worker that pops jobs off a queue only needs +@read +blpop +brpop. Figure out what your app actually calls โ€” ACL LOG can help โ€” and grant only that.

Lock down the default user in production

Unauthenticated connections shouldn't have any access. A standard production pattern:

user default off nopass ~* -@all

Now if your app forgets to send credentials, it gets a hard error instead of quietly connecting with full privileges. Named users handle all real access.

Test categories before going to production

It's easy to assume a command is in +@read when it's actually in +@string or +@sortedset. Before applying rules to a production user, I keep a terminal open with ACL CAT <category> to double-check. Takes 10 seconds and saves a lot of late-night debugging.

Related Error Notes