{
  "schema_version": 2,
  "id": "operate/oss_and_stack/management/security/acl",
  "title": "ACL",
  "url": "https://redis.io/docs/latest/operate/oss_and_stack/management/security/acl/",
  "summary": "Redis Access Control List",
  "aliases": [
    "/manual/security/acl/",
    "/management/security/acl/"
  ],
  "tags": [
    "docs",
    "operate",
    "stack",
    "oss"
  ],
  "last_updated": "2026-10-13T16:38:58+03:00",
  "page_type": "content",
  "content_hash": "1ee611511bbbaeb6d8eef46776ad1ad000217b5e198db0e7ad25fc0c72d8d62d",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "The Redis ACL, short for Access Control List, is the feature that allows certain\nconnections to be limited in terms of the commands that can be executed and the\nkeys that can be accessed. The way it works is that, after connecting, a client\nis required to provide a username and a valid password to authenticate. If authentication succeeded, the connection is associated with a given\nuser and the limits the user has. Redis can be configured so that new\nconnections are already authenticated with a \"default\" user (this is the\ndefault configuration). Configuring the default user has, as a side effect,\nthe ability to provide only a specific subset of functionalities to connections\nthat are not explicitly authenticated.\n\nIn the default configuration, Redis 6 (the first version to have ACLs) works\nexactly like older versions of Redis. Every new connection is\ncapable of calling every possible command and accessing every key, so the\nACL feature is backward compatible with old clients and applications. Also\nthe old way to configure a password, using the **requirepass** configuration\ndirective, still works as expected. However, it now\nsets a password for the default user.\n\nThe Redis [`AUTH`](https://redis.io/docs/latest/commands/auth) command was extended in Redis 6, so now it is possible to\nuse it in the two-arguments form:\n\n    AUTH <username> <password>\n\nHere's an example of the old form:\n\n    AUTH <password>\n\nWhat happens is that the username used to authenticate is \"default\", so\njust specifying the password implies that we want to authenticate against\nthe default user. This provides backward compatibility."
    },
    {
      "id": "when-acls-are-useful",
      "title": "When ACLs are useful",
      "role": "content",
      "text": "Before using ACLs, you may want to ask yourself what's the goal you want to\naccomplish by implementing this layer of protection. Normally there are\ntwo main goals that are well served by ACLs:\n\n1. You want to improve security by restricting the access to commands and keys, so that untrusted clients have no access and trusted clients have just the minimum access level to the database in order to perform the work needed. For instance, certain clients may just be able to execute read only commands.\n2. You want to improve operational safety, so that processes or humans accessing Redis are not allowed to damage the data or the configuration because of software errors or manual mistakes. For example, a worker that fetches delayed jobs from Redis does not need permission to call [`FLUSHALL`](https://redis.io/docs/latest/commands/flushall), [`FLUSHDB`](https://redis.io/docs/latest/commands/flushdb), or [`SWAPDB`](https://redis.io/docs/latest/commands/swapdb).\n\nAnother typical usage of ACLs is related to managed Redis instances. Redis is\noften provided as a managed service both by internal company teams that handle\nthe Redis infrastructure for the other internal customers they have, or is\nprovided in a software-as-a-service setup by cloud providers. In both \nsetups, we want to be sure that configuration commands are excluded for the\ncustomers."
    },
    {
      "id": "configure-acls-with-the-acl-command",
      "title": "Configure ACLs with the ACL command",
      "role": "configuration",
      "text": "ACLs are defined using a DSL (domain specific language) that describes what\na given user is allowed to do. Such rules are always implemented from the\nfirst to the last, left-to-right, because sometimes the order of the rules is\nimportant to understand what the user is really able to do.\n\nBy default there is a single user defined, called *default*. We\ncan use the [`ACL LIST`](https://redis.io/docs/latest/commands/acl-list) command in order to check the currently active ACLs\nand verify what the configuration of a freshly started, defaults-configured\nRedis instance is:\n\n    > ACL LIST\n    1) \"user default on nopass ~* &* +@all\"\n\nThe command above reports the list of users in the same format that is\nused in the Redis configuration files, by translating the current ACLs set\nfor the users back into their description.\n\nThe first two words in each line are \"user\" followed by the username. The\nnext words are ACL rules that describe different things. We'll show how the rules work in detail, but for now it is enough to say that the default\nuser is configured to be active (on), to require no password (nopass), to\naccess every possible key (`~*`) and Pub/Sub channel (`&*`), and be able to\ncall every possible command (`+@all`).\n\nAlso, in the special case of the default user, having the *nopass* rule means\nthat new connections are automatically authenticated with the default user\nwithout any explicit [`AUTH`](https://redis.io/docs/latest/commands/auth) call needed."
    },
    {
      "id": "acl-rules",
      "title": "ACL rules",
      "role": "security",
      "text": "The following is the list of valid ACL rules. Certain rules are just\nsingle words that are used in order to activate or remove a flag, or to\nperform a given change to the user ACL. Other rules are char prefixes that\nare concatenated with command or category names, key patterns, and\nso forth.\n\nEnable and disallow users:\n\n* `on`: Enable the user: it is possible to authenticate as this user.\n* `off`: Disallow the user: it's no longer possible to authenticate with this user; however, previously authenticated connections will still work. Note that if the default user is flagged as *off*, new connections will start as not authenticated and will require the user to send [`AUTH`](https://redis.io/docs/latest/commands/auth) or [`HELLO`](https://redis.io/docs/latest/commands/hello) with the AUTH option in order to authenticate in some way, regardless of the default user configuration.\n\nAllow and disallow commands:\n\n* `+<command>`: Add the command to the list of commands the user can call. Can be used with `|` for allowing subcommands (e.g \"+config|get\").\n* `-<command>`: Remove the command to the list of commands the user can call. Starting Redis 7.0, it can be used with `|` for blocking subcommands (e.g \"-config|set\").\n* `+@<category>`: Add all the commands in such category to be called by the user, with valid categories being like @admin, @set, @sortedset, ... and so forth, see the full list by calling the [`ACL CAT`](https://redis.io/docs/latest/commands/acl-cat) command. The special category @all means all the commands, both the ones currently present in the server, and the ones that will be loaded in the future via modules.\n* `-@<category>`: Like `+@<category>` but removes the commands from the list of commands the client can call.\n* `+<command>|first-arg`: Allow a specific first argument of an otherwise disabled command. It is only supported on commands with no sub-commands, and is not allowed as negative form like -SELECT|1, only additive starting with \"+\". This feature is deprecated and may be removed in the future.\n* `allcommands`: Alias for +@all. Note that it implies the ability to execute all the future commands loaded via the modules system.\n* `nocommands`: Alias for -@all.\n\nAllow and disallow certain keys and key permissions:\n\n* `~<pattern>`: Add a pattern of keys that can be mentioned as part of commands. For instance `~*` allows all the keys. The pattern is a glob-style pattern like the one of [`KEYS`](https://redis.io/docs/latest/commands/keys). It is possible to specify multiple patterns.\n* `%R~<pattern>`: (Available in Redis 7.0 and later) Add the specified read key pattern. This behaves similar to the regular key pattern but only grants permission to read from keys that match the given pattern. See [key permissions](#key-permissions) for more information.\n* `%W~<pattern>`: (Available in Redis 7.0 and later) Add the specified write key pattern. This behaves similar to the regular key pattern but only grants permission to write to keys that match the given pattern. See [key permissions](#key-permissions) for more information.\n* `%RW~<pattern>`: (Available in Redis 7.0 and later) Alias for `~<pattern>`. \n* `allkeys`: Alias for `~*`.\n* `resetkeys`: Flush the list of allowed keys patterns. For instance the ACL `~foo:* ~bar:* resetkeys ~objects:*`, will only allow the client to access keys that match the pattern `objects:*`.\n\nAllow and disallow Pub/Sub channels:\n\n* `&<pattern>`: (Available in Redis 6.2 and later) Add a glob style pattern of Pub/Sub channels that can be accessed by the user. It is possible to specify multiple channel patterns. Note that pattern matching is done only for channels mentioned by [`PUBLISH`](https://redis.io/docs/latest/commands/publish) and [`SUBSCRIBE`](https://redis.io/docs/latest/commands/subscribe), whereas [`PSUBSCRIBE`](https://redis.io/docs/latest/commands/psubscribe) requires a literal match between its channel patterns and those allowed for user.\n* `allchannels`: Alias for `&*` that allows the user to access all Pub/Sub channels.\n* `resetchannels`: Flush the list of allowed channel patterns and disconnect the user's Pub/Sub clients if these are no longer able to access their respective channels and/or channel patterns.\n\nConfigure valid passwords for the user:\n\n* `><password>`: Add this password to the list of valid passwords for the user. For example `>mypass` will add \"mypass\" to the list of valid passwords.  This directive clears the *nopass* flag (see later). Every user can have any number of passwords.\n* `<<password>`: Remove this password from the list of valid passwords. Emits an error in case the password you are trying to remove is actually not set.\n* `#<hash>`: Add this SHA-256 hash value to the list of valid passwords for the user. This hash value will be compared to the hash of a password entered for an ACL user. This allows users to store hashes in the `acl.conf` file rather than storing cleartext passwords. Only SHA-256 hash values are accepted as the password hash must be 64 characters and only contain lowercase hexadecimal characters.\n* `!<hash>`: Remove this hash value from the list of valid passwords. This is useful when you do not know the password specified by the hash value but would like to remove the password from the user.\n* `nopass`: All the set passwords of the user are removed, and the user is flagged as requiring no password: it means that every password will work against this user. If this directive is used for the default user, every new connection will be immediately authenticated with the default user without any explicit AUTH command required. Note that the *resetpass* directive will clear this condition.\n* `resetpass`: Flushes the list of allowed passwords and removes the *nopass* status. After *resetpass*, the user has no associated passwords and there is no way to authenticate without adding some password (or setting it as *nopass* later).\n\n*Note: if a user is not flagged with nopass and has no list of valid passwords, that user is effectively impossible to use because there will be no way to log in as that user.*\n\nConfigure selectors for the user:\n\n* `(<rule list>)`: (Available in Redis 7.0 and later) Create a new selector to match rules against. Selectors are evaluated after the user permissions, and are evaluated according to the order they are defined. If a command matches either the user permissions or any selector, it is allowed. See [selectors](#selectors) for more information.\n* `clearselectors`: (Available in Redis 7.0 and later) Delete all of the selectors attached to the user.\n\nReset the user:\n\n* `reset` Performs the following actions: resetpass, resetkeys, resetchannels, allchannels (if acl-pubsub-default is set), off, clearselectors, -@all. The user returns to the same state it had immediately after its creation."
    },
    {
      "id": "create-and-edit-user-acls-with-the-acl-setuser-command",
      "title": "Create and edit user ACLs with the ACL SETUSER command",
      "role": "content",
      "text": "Users can be created and modified in two main ways:\n\n1. Using the ACL command and its [`ACL SETUSER`](https://redis.io/docs/latest/commands/acl-setuser) subcommand.\n2. Modifying the server configuration, where users can be defined, and restarting the server. With an *external ACL file*, just call [`ACL LOAD`](https://redis.io/docs/latest/commands/acl-load).\n\nIn this section we'll learn how to define users using the [`ACL`](https://redis.io/docs/latest/commands/acl) command.\nWith such knowledge, it will be trivial to do the same things via the\nconfiguration files. Defining users in the configuration deserves its own\nsection and will be discussed later separately.\n\nTo start, try the simplest [`ACL SETUSER`](https://redis.io/docs/latest/commands/acl-setuser) command call:\n\n    > ACL SETUSER alice\n    OK\n\nThe [`ACL SETUSER`](https://redis.io/docs/latest/commands/acl-setuser) command takes the username and a list of ACL rules to apply\nto the user. However the above example did not specify any rule at all.\nThis will just create the user if it did not exist, using the defaults for new\nusers. If the user already exists, the command above will do nothing at all.\n\nCheck the default user status:\n\n    > ACL LIST\n    1) \"user alice off resetchannels -@all\"\n    2) \"user default on nopass ~* &* +@all\"\n\nThe new user \"alice\" is:\n\n* In the off status, so [`AUTH`](https://redis.io/docs/latest/commands/auth) will not work for the user \"alice\".\n* The user also has no passwords set.\n* Cannot access any command. Note that the user is created by default without the ability to access any command, so the `-@all` in the output above could be omitted; however, [`ACL LIST`](https://redis.io/docs/latest/commands/acl-list) attempts to be explicit rather than implicit.\n* There are no key patterns that the user can access.\n* There are no Pub/Sub channels that the user can access.\n\nNew users are created with restrictive permissions by default. Starting with Redis 6.2, ACL provides Pub/Sub channels access management as well. To ensure backward compatibility with version 6.0 when upgrading to Redis 6.2, new users are granted the 'allchannels' permission by default. The default can be set to `resetchannels` via the `acl-pubsub-default` configuration directive.\n\nFrom 7.0, The `acl-pubsub-default` value is set to `resetchannels` to restrict the channels access by default to provide better security.\nThe default can be set to `allchannels` via the `acl-pubsub-default` configuration directive to be compatible with previous versions.\n\nSuch user is completely useless. Let's try to define the user so that\nit is active, has a password, and can access with only the [`GET`](https://redis.io/docs/latest/commands/get) command\nto key names starting with the string \"cached:\".\n\n    > ACL SETUSER alice on >p1pp0 ~cached:* +get\n    OK\n\nNow the user can do something, but will refuse to do other things:\n\n    > AUTH alice p1pp0\n    OK\n    > GET foo\n    (error) NOPERM this user has no permissions to access one of the keys used as arguments\n    > GET cached:1234\n    (nil)\n    > SET cached:1234 zap\n    (error) NOPERM this user has no permissions to run the 'set' command\n\nThings are working as expected. In order to inspect the configuration of the\nuser alice (remember that user names are case sensitive), it is possible to\nuse an alternative to [`ACL LIST`](https://redis.io/docs/latest/commands/acl-list) which is designed to be more suitable for\ncomputers to read, while [`ACL GETUSER`](https://redis.io/docs/latest/commands/acl-getuser) is more human readable.\n\n    > ACL GETUSER alice\n    1) \"flags\"\n    2) 1) \"on\"\n    3) \"passwords\"\n    4) 1) \"2d9c75...\"\n    5) \"commands\"\n    6) \"-@all +get\"\n    7) \"keys\"\n    8) \"~cached:*\"\n    9) \"channels\"\n    10) \"\"\n    11) \"selectors\"\n    12) (empty array)\n\nThe [`ACL GETUSER`](https://redis.io/docs/latest/commands/acl-getuser) returns a field-value array that describes the user in more parsable terms. The output includes the set of flags, a list of key patterns, passwords, and so forth. The output is probably more readable if we use RESP3, so that it is returned as a map reply:\n\n    > ACL GETUSER alice\n    1# \"flags\" => 1~ \"on\"\n    2# \"passwords\" => 1) \"2d9c75273d72b32df726fb545c8a4edc719f0a95a6fd993950b10c474ad9c927\"\n    3# \"commands\" => \"-@all +get\"\n    4# \"keys\" => \"~cached:*\"\n    5# \"channels\" => \"\"\n    6# \"selectors\" => (empty array)\n\n*Note: from now on, we'll continue using the Redis default protocol, version 2*\n\nUsing another [`ACL SETUSER`](https://redis.io/docs/latest/commands/acl-setuser) command (from a different user, because alice cannot run the [`ACL`](https://redis.io/docs/latest/commands/acl) command), we can add multiple patterns to the user:\n\n    > ACL SETUSER alice ~objects:* ~items:* ~public:*\n    OK\n    > ACL LIST\n    1) \"user alice on #2d9c75... ~cached:* ~objects:* ~items:* ~public:* resetchannels -@all +get\"\n    2) \"user default on nopass ~* &* +@all\"\n\nThe user representation in memory is now as we expect it to be."
    },
    {
      "id": "multiple-calls-to-acl-setuser",
      "title": "Multiple calls to ACL SETUSER",
      "role": "content",
      "text": "It is very important to understand what happens when [`ACL SETUSER`](https://redis.io/docs/latest/commands/acl-setuser) is called\nmultiple times. What is critical to know is that every [`ACL SETUSER`](https://redis.io/docs/latest/commands/acl-setuser) call will\nNOT reset the user, but will just apply the ACL rules to the existing user.\nThe user is reset only if it was not known before. In that case, a brand new\nuser is created with zeroed-ACLs. The user cannot do anything, is\ndisallowed, has no passwords, and so forth. This is the best default for safety.\n\nHowever later calls will just modify the user incrementally. For instance,\nthe following sequence:\n\n    > ACL SETUSER myuser +set\n    OK\n    > ACL SETUSER myuser +get\n    OK\n\nWill result in myuser being able to call both [`GET`](https://redis.io/docs/latest/commands/get) and [`SET`](https://redis.io/docs/latest/commands/set):\n\n    > ACL LIST\n    1) \"user default on nopass ~* &* +@all\"\n    2) \"user myuser off resetchannels -@all +get +set\""
    },
    {
      "id": "command-categories",
      "title": "Command categories",
      "role": "syntax",
      "text": "Setting user ACLs by specifying all the commands one after the other is\nreally annoying, so instead we do things like this:\n\n    > ACL SETUSER antirez on +@all -@dangerous >42a979... ~*\n\nThe above command includes all commands (`+@all`) and then removes all commands tagged as dangerous (`-@dangerous`) inside the Redis command table.\nNote that command categories, with the exception of `+@all`, never include module commands.\n\nIf you use `+@all` for a particular user, all commands are available to that user, including commands loaded via the modules system. However, if you use `+@read` or any other, module commands are excluded. This concept is fundamental because you should only trust the Redis\ninternal command table. Modules may expose dangerous things, and in\nthe case of an ACL that is just additive, that is, in the form of `+@all -...`,\nyou should be absolutely sure that you won't include what you did not mean to.\n\nThe following is a list of command categories and their meanings:\n\n* <a id=\"admin\"></a>**admin** - Administrative commands. Normal applications will never need to use\n  these. Includes [`REPLICAOF`](https://redis.io/docs/latest/commands/replicaof), [`CONFIG`](https://redis.io/docs/latest/commands/config), [`DEBUG`](https://redis.io/docs/latest/commands/debug), [`SAVE`](https://redis.io/docs/latest/commands/save), [`MONITOR`](https://redis.io/docs/latest/commands/monitor), [`ACL`](https://redis.io/docs/latest/commands/acl), [`SHUTDOWN`](https://redis.io/docs/latest/commands/shutdown), etc.\n* <a id=\"array\"></a>**array** - Data type: all array related commands.\n* <a id=\"bitmap\"></a>**bitmap** - Data type: all bitmap related commands.\n* <a id=\"blocking\"></a>**blocking** - Potentially blocking the connection until released by another\n  command.\n* <a id=\"bloom\"></a>**bloom** - Data type: all Bloom filter related commands. <sup>[1](#cmd-note-1)</sup>\n* <a id=\"cms\"></a>**cms** - Data type: count-min sketch related commands. <sup>[1](#cmd-note-1)</sup>\n* <a id=\"connection\"></a>**connection** - Commands affecting the connection or other connections.\n  This includes [`AUTH`](https://redis.io/docs/latest/commands/auth), [`SELECT`](https://redis.io/docs/latest/commands/select), [`COMMAND`](https://redis.io/docs/latest/commands/command), [`CLIENT`](https://redis.io/docs/latest/commands/client), [`ECHO`](https://redis.io/docs/latest/commands/echo), [`PING`](https://redis.io/docs/latest/commands/ping), etc.\n* <a id=\"cuckoo\"></a>**cuckoo** - Data type: all Cuckoo filter related commands. <sup>[1](#cmd-note-1)</sup>\n* <a id=\"dangerous\"></a>**dangerous** - Potentially dangerous commands (each should be considered with care for\n  various reasons). This includes [`FLUSHALL`](https://redis.io/docs/latest/commands/flushall), [`MIGRATE`](https://redis.io/docs/latest/commands/migrate), [`RESTORE`](https://redis.io/docs/latest/commands/restore), [`SORT`](https://redis.io/docs/latest/commands/sort), [`KEYS`](https://redis.io/docs/latest/commands/keys),\n  [`CLIENT`](https://redis.io/docs/latest/commands/client), [`DEBUG`](https://redis.io/docs/latest/commands/debug), [`INFO`](https://redis.io/docs/latest/commands/info), [`CONFIG`](https://redis.io/docs/latest/commands/config), [`SAVE`](https://redis.io/docs/latest/commands/save), [`REPLICAOF`](https://redis.io/docs/latest/commands/replicaof), etc.\n* <a id=\"fast\"></a>**fast** - Fast O(1) commands. May loop on the number of arguments, but not the number of elements in the key.\n* <a id=\"geo\"></a>**geo** - Data type: all geospatial index related commands.\n* <a id=\"hash\"></a>**hash** - Data type: all hash related commands.\n* <a id=\"hyperloglog\"></a>**hyperloglog** - Data type: all hyperloglog related commands.\n* <a id=\"json\"></a>**json** - Data type: all JSON related commands. <sup>[1](#cmd-note-1)</sup>\n* <a id=\"keyspace\"></a>**keyspace** - Writing or reading from keys, databases, or their metadata\n  in a type agnostic way. Includes [`DEL`](https://redis.io/docs/latest/commands/del), [`RESTORE`](https://redis.io/docs/latest/commands/restore), [`DUMP`](https://redis.io/docs/latest/commands/dump), [`RENAME`](https://redis.io/docs/latest/commands/rename), [`EXISTS`](https://redis.io/docs/latest/commands/exists), [`DBSIZE`](https://redis.io/docs/latest/commands/dbsize),\n  [`KEYS`](https://redis.io/docs/latest/commands/keys), [`SCAN`](https://redis.io/docs/latest/commands/scan), [`EXPIRE`](https://redis.io/docs/latest/commands/expire), [`TTL`](https://redis.io/docs/latest/commands/ttl), [`FLUSHALL`](https://redis.io/docs/latest/commands/flushall), etc. Commands that may modify the keyspace,\n  key, or metadata will also have the `write` category. Commands that only read\n  the keyspace, key, or metadata will have the `read` category.\n* <a id=\"list\"></a>**list** - Data type: all list related commands.\n* <a id=\"pubsub\"></a>**pubsub** - all pubsub related commands.\n* <a id=\"read\"></a>**read** - Reading from keys (values or metadata). Note that commands that don't interact with keys, will not have either `read` or `write`.\n* <a id=\"scripting\"></a>**scripting** - Scripting related.\n* <a id=\"search\"></a>**search** - All search related commands. Only ACL users with access to a superset of the key prefixes defined during index creation can create, modify, or read the index. For example, a user with the key ACL pattern `h:*` can create an index with keys prefixed by `h:*` or `h:p*`, but not keys prefixed by `h*`, `k:*`, or `k*`, because these prefixes may involve keys to which the user does not have access. <sup>[1](#cmd-note-1)</sup>\n* <a id=\"set\"></a>**set** - Data type: all set related commands.\n* <a id=\"sortedset\"></a>**sortedset** - Data type: all sorted set related commands.\n* <a id=\"slow\"></a>**slow** - All commands that are not `fast`.\n* <a id=\"stream\"></a>**stream** - Data type: all stream related commands.\n* <a id=\"string\"></a>**string** - Data type: all string related commands.\n* <a id=\"tdigest\"></a>**tdigest** - Data type: all t-digest related commands. <sup>[1](#cmd-note-1)</sup>\n* <a id=\"timeseries\"></a>**timeseries** - Data type: all time series related commands. <sup>[1](#cmd-note-1)</sup>\n* <a id=\"topk\"></a>**topk** - Data type: all top-k related commands. <sup>[1](#cmd-note-1)</sup>\n* <a id=\"transaction\"></a>**transaction** - [`WATCH`](https://redis.io/docs/latest/commands/watch) / [`MULTI`](https://redis.io/docs/latest/commands/multi) / [`EXEC`](https://redis.io/docs/latest/commands/exec) related commands.\n* <a id=\"write\"></a>**write** - Writing to keys (values or metadata). Note that commands that don't interact with keys, will not have either `read` or `write`.\n\n1. <a name=\"cmd-note-1\"></a> See the [Redis 8 release notes](https://redis.io/docs/latest/operate/oss_and_stack/stack-with-enterprise/release-notes/redisce/redisos-8.0-release-notes#potentially-breaking-changes-to-acls) for more information about these command categories, which may introduce breaking changes to your Redis deployments.\n\nNOTE: Redis can also show you a list of all categories and the exact commands each category includes using the Redis [`ACL CAT`](https://redis.io/docs/latest/commands/acl-cat) command. \nIt can be used in two forms:\n\n    ACL CAT -- Will just list all the categories available\n    ACL CAT <category-name> -- Will list all the commands inside the category\n\nExamples:\n\n[code example]\n\nAs you can see, so far there are 29 distinct categories. Now let's check what\ncommand is part of the *geo* category:\n\n[code example]\n\nNote that commands may be part of multiple categories. For example, an\nACL rule like `+@geo -@read` will result in certain geo commands to be\nexcluded because they are read-only commands."
    },
    {
      "id": "allowblock-subcommands",
      "title": "Allow/block subcommands",
      "role": "content",
      "text": "Starting from Redis 7.0, subcommands can be allowed/blocked just like other\ncommands (by using the separator `|` between the command and subcommand, for\nexample: `+config|get` or `-config|set`)\n\nThat is true for all commands except DEBUG. In order to allow/block specific\nDEBUG subcommands, see the next section."
    },
    {
      "id": "allow-the-first-arg-of-a-blocked-command",
      "title": "Allow the first-arg of a blocked command",
      "role": "content",
      "text": "**Note: This feature is deprecated since Redis 7.0 and may be removed in the future.**\n\nSometimes the ability to exclude or include a command or a subcommand as a whole is not enough.\nMany deployments may not be happy providing the ability to execute a [`SELECT`](https://redis.io/docs/latest/commands/select) for any DB, but may\nstill want to be able to run `SELECT 0`.\n\nIn such case we could alter the ACL of a user in the following way:\n\n    ACL SETUSER myuser -select +select|0\n\nFirst, remove the [`SELECT`](https://redis.io/docs/latest/commands/select) command and then add the allowed\nfirst-arg. Note that **it is not possible to do the reverse** since first-args\ncan be only added, not excluded. It is safer to specify all the first-args\nthat are valid for some user since it is possible that\nnew first-args may be added in the future.\n\nAnother example:\n\n    ACL SETUSER myuser -debug +debug|digest\n\nNote that first-arg matching may add some performance penalty; however, it is hard to measure even with synthetic benchmarks. The\nadditional CPU cost is only paid when such commands are called, and not when\nother commands are called.\n\nIt is possible to use this mechanism in order to allow subcommands in Redis\nversions prior to 7.0 (see above section)."
    },
    {
      "id": "all-vs--all",
      "title": "+@all VS -@all",
      "role": "content",
      "text": "In the previous section, it was observed how it is possible to define command\nACLs based on adding/removing single commands."
    },
    {
      "id": "selectors",
      "title": "Selectors",
      "role": "content",
      "text": "Starting with Redis 7.0, Redis supports adding multiple sets of rules that are evaluated independently of each other.\nThese secondary sets of permissions are called selectors and added by wrapping a set of rules within parentheses.\nIn order to execute a command, either the root permissions (rules defined outside of parenthesis) or any of the selectors (rules defined inside parenthesis) must match the given command.\nInternally, the root permissions are checked first followed by selectors in the order they were added.\n\nFor example, consider a user with the ACL rules `+GET ~key1 (+SET ~key2)`.\nThis user is able to execute `GET key1` and `SET key2 hello`, but not `GET key2` or `SET key1 world`.\n\nUnlike the user's root permissions, selectors cannot be modified after they are added.\nInstead, selectors can be removed with the `clearselectors` keyword, which removes all of the added selectors.\nNote that `clearselectors` does not remove the root permissions."
    },
    {
      "id": "key-permissions",
      "title": "Key permissions",
      "role": "content",
      "text": "Starting with Redis 7.0, key patterns can also be used to define how a command is able to touch a key.\nThis is achieved through rules that define key permissions.\nThe key permission rules take the form of `%(<permission>)~<pattern>`.\nPermissions are defined as individual characters that map to the following key permissions:\n\n* W (Write): The data stored within the key may be updated or deleted. \n* R (Read): User supplied data from the key is processed, copied or returned. Note that this does not include metadata such as size information (example [`STRLEN`](https://redis.io/docs/latest/commands/strlen)), type information (example [`TYPE`](https://redis.io/docs/latest/commands/type)) or information about whether a value exists within a collection (example [`SISMEMBER`](https://redis.io/docs/latest/commands/sismember)). \n\nPermissions can be composed together by specifying multiple characters. \nSpecifying the permission as 'RW' is considered full access and is analogous to just passing in `~<pattern>`.\n\nFor a concrete example, consider a user with ACL rules `+@all ~app1:* (+@read ~app2:*)`.\nThis user has full access on `app1:*` and readonly access on `app2:*`.\nHowever, some commands support reading data from one key, doing some transformation, and storing it into another key.\nOne such command is the [`COPY`](https://redis.io/docs/latest/commands/copy) command, which copies the data from the source key into the destination key.\nThe example set of ACL rules is unable to handle a request copying data from `app2:user` into `app1:user`, since neither the root permission nor the selector fully matches the command.\nHowever, using key selectors you can define a set of ACL rules that can handle this request `+@all ~app1:* %R~app2:*`.\nThe first pattern is able to match `app1:user` and the second pattern is able to match `app2:user`.\n\nWhich type of permission is required for a command is documented through [key specifications](https://redis.io/docs/latest/develop/reference/key-specs#logical-operation-flags).\nThe type of permission is based off the keys logical operation flags. \nThe insert, update, and delete flags map to the write key permission. \nThe access flag maps to the read key permission.\nIf the key has no logical operation flags, such as [`EXISTS`](https://redis.io/docs/latest/commands/exists), the user still needs either key read or key write permissions to execute the command. \n\nNote: Side channels to accessing user data are ignored when it comes to evaluating whether read permissions are required to execute a command.\nThis means that some write commands that return metadata about the modified key only require write permission on the key to execute.\nFor example, consider the following two commands:\n\n* `LPUSH key1 data`: modifies \"key1\" but only returns metadata about it, the size of the list after the push, so the command only requires write permission on \"key1\" to execute.\n* `LPOP key2`: modifies \"key2\" but also returns data from it, the left most item in the list, so the command requires both read and write permission on \"key2\" to execute.\n\nIf an application needs to make sure no data is accessed from a key, including side channels, it's recommended to not provide any access to the key.\n\n> [!NOTE]\n> Key patterns only restrict commands that operate on specific keys named in the command's arguments. Commands that operate on an entire database or the whole keyspace, and therefore take no key arguments, are not limited by key patterns. Such commands are governed only by command and [category](#command-categories) rules.\n\nThis includes commands that can destroy or replace data beyond a user's key patterns, such as [`FLUSHALL`](https://redis.io/docs/latest/commands/flushall), [`FLUSHDB`](https://redis.io/docs/latest/commands/flushdb), and [`SWAPDB`](https://redis.io/docs/latest/commands/swapdb).\n\nFor example, a user defined with `~tenant1:* +@all` can still run `FLUSHALL` to delete every key in the database, even though its key pattern only matches `tenant1:*`. To prevent this, remove those commands explicitly:\n\n    > ACL SETUSER tenant1 on >strong-password ~tenant1:* +@all -flushall -flushdb -swapdb"
    },
    {
      "id": "how-passwords-are-stored-internally",
      "title": "How passwords are stored internally",
      "role": "content",
      "text": "Redis internally stores passwords hashed with SHA256. If you set a password\nand check the output of [`ACL LIST`](https://redis.io/docs/latest/commands/acl-list) or [`ACL GETUSER`](https://redis.io/docs/latest/commands/acl-getuser), you'll see a long hex\nstring that looks pseudo random. Here is an example, because in the previous\nexamples, for the sake of brevity, the long hex string was trimmed:\n\n[code example]\n\nUsing SHA256 provides the ability to avoid storing the password in clear text\nwhile still allowing for a very fast [`AUTH`](https://redis.io/docs/latest/commands/auth) command, which is a very important\nfeature of Redis and is coherent with what clients expect from Redis.\n\nHowever ACL *passwords* are not really passwords. They are shared secrets\nbetween the server and the client, because the password is\nnot an authentication token used by a human being. For instance:\n\n* There are no length limits, the password will just be memorized in some client software. There is no human that needs to recall a password in this context.\n* The ACL password does not protect any other thing. For example, it will never be the password for some email account.\n* Often when you are able to access the hashed password itself, by having full access to the Redis commands of a given server, or corrupting the system itself, you already have access to what the password is protecting: the Redis instance stability and the data it contains.\n\nFor this reason, slowing down the password authentication, in order to use an\nalgorithm that uses time and space to make password cracking hard,\nis a very poor choice. What we suggest instead is to generate strong\npasswords, so that nobody will be able to crack it using a\ndictionary or a brute force attack even if they have the hash. To do so, there is a special ACL\ncommand [`ACL GENPASS`](https://redis.io/docs/latest/commands/acl-genpass) that generates passwords using the system cryptographic pseudorandom\ngenerator:\n\n    > ACL GENPASS\n    \"dd721260bfe1b3d9601e7fbab36de6d04e2e67b0ef1c53de59d45950db0dd3cc\"\n\nThe command outputs a 32-byte (256-bit) pseudorandom string converted to a\n64-byte alphanumerical string. This is long enough to avoid attacks and short\nenough to be easy to manage, cut & paste, store, and so forth. This is what\nyou should use in order to generate Redis passwords."
    },
    {
      "id": "use-an-external-acl-file",
      "title": "Use an external ACL file",
      "role": "content",
      "text": "There are two ways to store users inside the Redis configuration:\n\n1. Users can be specified directly inside the `redis.conf` file.\n2. It is possible to specify an external ACL file.\n\nThe two methods are *mutually incompatible*, so Redis will ask you to use one\nor the other. Specifying users inside `redis.conf` is\ngood for simple use cases. When there are multiple users to define, in a\ncomplex environment, we recommend you use the ACL file instead.\n\nThe format used inside `redis.conf` and in the external ACL file is exactly\nthe same, so it is trivial to switch from one to the other, and is\nthe following:\n\n    user <username> ... acl rules ...\n\nFor instance:\n\n    user worker +@list +@connection ~jobs:* on >ffa9203c493aa99\n\nWhen you want to use an external ACL file, you are required to specify\nthe configuration directive called `aclfile`, like this:\n\n    aclfile /etc/redis/users.acl\n\nWhen you are just specifying a few users directly inside the `redis.conf`\nfile, you can use [`CONFIG REWRITE`](https://redis.io/docs/latest/commands/config-rewrite) in order to store the new user configuration\ninside the file by rewriting it.\n\nThe external ACL file however is more powerful. You can do the following:\n\n* Use [`ACL LOAD`](https://redis.io/docs/latest/commands/acl-load) if you modified the ACL file manually and you want Redis to reload the new configuration. Note that this command is able to load the file *only if all the users are correctly specified*. Otherwise, an error is reported to the user, and the old configuration will remain valid.\n* Use [`ACL SAVE`](https://redis.io/docs/latest/commands/acl-save) to save the current ACL configuration to the ACL file.\n\nNote that [`CONFIG REWRITE`](https://redis.io/docs/latest/commands/config-rewrite) does not also trigger [`ACL SAVE`](https://redis.io/docs/latest/commands/acl-save). When you use\nan ACL file, the configuration and the ACLs are handled separately.\n\nStarting with Redis 8.8, the `ACL LOAD` command will allow comment lines starting with the `#` character. Any such comment lines are stripped when the ACL file is loaded and they are not persisted across `ACL LOAD`/`ACL SAVE` commands."
    },
    {
      "id": "acl-rules-for-sentinel-and-replicas",
      "title": "ACL rules for Sentinel and Replicas",
      "role": "security",
      "text": "In case you don't want to provide Redis replicas and Redis Sentinel instances\nfull access to your Redis instances, the following is the set of commands\nthat must be allowed in order for everything to work correctly.\n\nFor Sentinel, allow the user to access the following commands both in the master and replica instances:\n\n* AUTH, CLIENT, SUBSCRIBE, SCRIPT, PUBLISH, PING, INFO, MULTI, SLAVEOF, CONFIG, CLIENT, EXEC.\n\nSentinel does not need to access any key in the database but does use Pub/Sub, so the ACL rule would be the following (note: [`AUTH`](https://redis.io/docs/latest/commands/auth) is not needed since it is always allowed):\n\n    ACL SETUSER sentinel-user on >somepassword resetchannels &__sentinel__:hello +multi +slaveof +ping +exec +subscribe +config|rewrite +role +publish +info +client|setname +client|kill +script|kill\n\nRedis replicas require the following commands to be allowed on the master instance:\n\n* PSYNC, REPLCONF, PING\n\nNo keys need to be accessed, so this translates to the following rules:\n\n    ACL setuser replica-user on >somepassword +psync +replconf +ping\n\nNote that you don't need to configure the replicas to allow the master to be able to execute any set of commands. The master is always authenticated as the root user from the point of view of replicas."
    }
  ],
  "examples": [
    {
      "id": "command-categories-ex0",
      "language": "plaintext",
      "code": "> ACL CAT\n 1) \"keyspace\"\n 2) \"read\"\n 3) \"write\"\n 4) \"set\"\n 5) \"sortedset\"\n 6) \"list\"\n 7) \"hash\"\n 8) \"string\"\n 9) \"bitmap\"\n10) \"hyperloglog\"\n11) \"geo\"\n12) \"stream\"\n13) \"pubsub\"\n14) \"admin\"\n15) \"fast\"\n16) \"slow\"\n17) \"blocking\"\n18) \"dangerous\"\n19) \"connection\"\n20) \"transaction\"\n21) \"scripting\"\n22) \"json\"\n23) \"search\"\n24) \"tdigest\"\n25) \"cms\"\n26) \"bloom\"\n27) \"cuckoo\"\n28) \"topk\"\n29) \"timeseries\"",
      "section_id": "command-categories"
    },
    {
      "id": "command-categories-ex1",
      "language": "plaintext",
      "code": "> ACL CAT geo\n1) \"geohash\"\n2) \"georadius_ro\"\n3) \"georadiusbymember\"\n4) \"geopos\"\n5) \"geoadd\"\n6) \"georadiusbymember_ro\"\n7) \"geodist\"\n8) \"georadius\"\n9) \"geosearch\"\n10) \"geosearchstore\"",
      "section_id": "command-categories"
    },
    {
      "id": "how-passwords-are-stored-internally-ex0",
      "language": "plaintext",
      "code": "> ACL GETUSER default\n1) \"flags\"\n2) 1) \"on\"\n3) \"passwords\"\n4) 1) \"2d9c75273d72b32df726fb545c8a4edc719f0a95a6fd993950b10c474ad9c927\"\n5) \"commands\"\n6) \"+@all\"\n7) \"keys\"\n8) \"~*\"\n9) \"channels\"\n10) \"&*\"\n11) \"selectors\"\n12) (empty array)",
      "section_id": "how-passwords-are-stored-internally"
    }
  ]
}
