# ACL

> Create users with their own passwords, commands, keys and channels, store them in an ACL file, and audit denied access.

URL: https://docs.hotkv.com/operate/acl/


**Availability:** All HotKV Cloud plans. On-Premise: no license needed.

Access control lists (ACL) let several users share one HotKV server, each
with its own passwords and its own set of allowed commands, keys and
pub/sub channels. Use them to give an application only the commands it
needs, to hand out read-only access, or to keep administrative commands
away from client code. The rule syntax is the one Redis 7 uses, so
existing rules and tools carry over.

For a short overview alongside TLS and protected mode, see
[Security](https://docs.hotkv.com/security/index.md#acl).

## The default user

Every server has a user named `default`. Out of the box it is on, needs no
password and may run every command on every key and channel:

```
127.0.0.1:6379> ACL LIST
1) "user default on nopass sanitize-payload ~* &* +@all"
```

A connection that has not authenticated runs as `default`. Setting
`requirepass` gives `default` that password, so every client must
authenticate first; `ACL SETUSER default ...` or a `user default` line in
the ACL file does the same with full ACL rules. While `default` has no
password, [protected mode](https://docs.hotkv.com/security/index.md#protected-mode) serves only clients
on a loopback address.

```
requirepass "a-long-random-password"
```

`CONFIG SET requirepass` changes the password at runtime (replacing any
other passwords of `default`). `CONFIG GET requirepass` answers `(hidden)`
once a password is set, not the password itself. The `default` user cannot
be deleted; turn it `off` instead to make every client log in as a named
user.

## Authenticate

Clients authenticate with `AUTH`:

```
127.0.0.1:6379> AUTH a-long-random-password
OK
127.0.0.1:6379> AUTH reports reports-password
OK
127.0.0.1:6379> AUTH reports wrong
(error) WRONGPASS invalid username-password pair or user is disabled.
```

`AUTH password` logs in as `default`; `AUTH username password` as any user.
Until a client authenticates on a server that requires it, commands fail
with `NOAUTH Authentication required.`. `AUTH password` on a server whose
`default` user has no password fails with an error that says so.

`HELLO` can authenticate and pick the protocol in one step:

```
HELLO 3 AUTH reports reports-password SETNAME report-job
```

Every HotKV SDK takes a `username` and `password` (or a URL with both), and
`hotkv-cli` takes `--user` and `-a`; see [hotkv-cli](https://docs.hotkv.com/get-started/hotkv-cli/index.md#authentication).

## Create a user

`ACL SETUSER` creates a user or changes one. A new user starts **off**,
with no password and no permissions, so give it everything it needs in one
command:

```
127.0.0.1:6379> ACL SETUSER reports on >reports-password ~report:* -@all +@read
OK
127.0.0.1:6379> ACL LIST
1) "user default on nopass sanitize-payload ~* &* +@all"
2) "user reports on sanitize-payload #c0a6280be3d2bc0b927b0327bd24bcdde0512a384940aa55ee6caf5c365d7095 ~report:* resetchannels -@all +@read"
```

Passwords are stored and listed as SHA-256 digests (`#...`), never as
text. Rules apply left to right, and either all of them apply or none
does: one invalid rule leaves the user as it was and names the rule.

```
127.0.0.1:6379> ACL SETUSER reports +nosuchcommand
(error) ERR Error in ACL SETUSER modifier '+nosuchcommand': Unknown command or category name in ACL
```

Changes take effect at once, for connections already logged in as that
user too. Deleting a user with `ACL DELUSER` disconnects its clients.

Some common users:

```
# An application: everything except administrative and destructive commands
ACL SETUSER app on >app-password ~* &* +@all -@dangerous

# A cache client limited to its own keys
ACL SETUSER cache on >cache-password ~cache:* -@all +get +set +del +expire

# A worker that only consumes from its channels
ACL SETUSER events on >events-password resetchannels &events:* -@all +subscribe +psubscribe

# A monitoring agent
ACL SETUSER monitor on >monitor-password -@all +info +ping +client|list +slowlog|get
```

Generate strong passwords with `ACL GENPASS`, which returns 256 random bits
as 64 hex characters by default (`ACL GENPASS 128` for fewer).

## Rules

### User state and passwords

| Rule | Effect |
| --- | --- |
| `on` / `off` | Allow or block logins; an `off` user's open connections run no commands |
| `>password` | Add a password (a user can have several) |
| `<password` | Remove a password |
| `#digest` / `!digest` | Add or remove a password given as its SHA-256 digest (64 lowercase hex characters) |
| `nopass` | Accept any password, and remove the stored ones |
| `resetpass` | Remove every password, and `nopass` |
| `reset` | Back to a new user: off, no passwords, no permissions, no selectors |
| `sanitize-payload` / `skip-sanitize-payload` | Accepted and shown for compatibility; HotKV always checks `RESTORE` payloads |

### Commands

Command rules start from `-@all` (nothing) unless you give `+@all`
(`allcommands`), and later rules refine earlier ones:

| Rule | Effect |
| --- | --- |
| `+@all` / `allcommands` | Allow every command, and start the command rules over |
| `-@all` / `nocommands` | Allow no command, and start the command rules over |
| `+command` / `-command` | Allow or deny one command, all its subcommands included |
| `+command\|subcommand` / `-command\|subcommand` | Allow or deny one subcommand, such as `+config\|get` |
| `+command\|arg` | Allow a command that has no subcommands only with this first argument, such as `+select\|0` (allow only; to deny, deny the command) |
| `+@category` / `-@category` | Allow or deny every command in a category |

A command, subcommand or category that does not exist is an error, so a
typo cannot leave a command allowed by accident.

### Categories

`ACL CAT` lists the categories and `ACL CAT <category>` the commands and
subcommands in one:

`keyspace`, `read`, `write`, `set`, `sortedset`, `list`, `hash`, `string`,
`bitmap`, `hyperloglog`, `geo`, `stream`, `pubsub`, `admin`, `fast`,
`slow`, `blocking`, `dangerous`, `connection`, `transaction`, `scripting`,
`bloom`, `cms`, `topk`, `timeseries`.

They match Redis's core categories, plus `bloom`, `cms`, `topk` and
`timeseries` for HotKV's own data types. HotKV has no module categories
such as `@json` or `@search`. HotKV's administrative commands
(`LICENSE.*`, `TENANT.*`, `ENCRYPTION.*`, `REPLICATION.*`, `AUDIT.*`) are
in `@admin` and `@dangerous`, so `-@dangerous` keeps them away from
application users.

### Keys

| Rule | Effect |
| --- | --- |
| `~pattern` | Allow reading and writing keys that match the glob pattern |
| `%R~pattern` | Allow reading only |
| `%W~pattern` | Allow writing only |
| `%RW~pattern` | Same as `~pattern` |
| `allkeys` / `~*` | Allow every key |
| `resetkeys` | Remove all key patterns |

A command runs only if the user may use every key it names, for reading,
writing or both as the command does. Adding a pattern after `~*` is an
error: use `resetkeys` first.

### Channels

| Rule | Effect |
| --- | --- |
| `&pattern` | Allow publishing and subscribing to channels that match the glob pattern |
| `allchannels` / `&*` | Allow every channel |
| `resetchannels` | Remove all channel patterns |

`PSUBSCRIBE` is allowed only for a pattern that is one of the user's
channel patterns as written. New users get no channels, unless
`acl-pubsub-default` is `allchannels`. When a user loses a channel, its
clients subscribed to that channel are disconnected.

### Selectors

A selector is a second (third, ...) set of command, key and channel rules
in parentheses. A command runs when the user's main rules or one of its
selectors allow the command together with all its keys and channels:

```
ACL SETUSER svc on >svc-password ~svc:* -@all +@read (~shared:* +get +set)
```

This user can read `svc:*` keys, and also `GET` and `SET` `shared:*` keys.
`clearselectors` removes a user's selectors. `ACL GETUSER` shows each
selector's rules separately.

## Inspect and test

| Command | Use |
| --- | --- |
| [`ACL WHOAMI`](https://docs.hotkv.com/commands/acl-whoami/index.md) | The user of the current connection |
| [`ACL USERS`](https://docs.hotkv.com/commands/acl-users/index.md) | All user names |
| [`ACL LIST`](https://docs.hotkv.com/commands/acl-list/index.md) | All users as ACL file lines |
| [`ACL GETUSER user`](https://docs.hotkv.com/commands/acl-getuser/index.md) | One user's flags, password digests, commands, keys, channels and selectors (nil if there is no such user) |
| [`ACL CAT [category]`](https://docs.hotkv.com/commands/acl-cat/index.md) | The categories, or the commands in one |
| [`ACL DRYRUN user command [arg ...]`](https://docs.hotkv.com/commands/acl-dryrun/index.md) | Whether the user could run the command with these arguments |
| [`ACL SETUSER`](https://docs.hotkv.com/commands/acl-setuser/index.md) / [`ACL DELUSER`](https://docs.hotkv.com/commands/acl-deluser/index.md) | Change or delete users |
| [`ACL GENPASS [bits]`](https://docs.hotkv.com/commands/acl-genpass/index.md) | A random password |
| [`ACL LOG [count \| RESET]`](https://docs.hotkv.com/commands/acl-log/index.md) | Recent denials |
| [`ACL SAVE`](https://docs.hotkv.com/commands/acl-save/index.md) / [`ACL LOAD`](https://docs.hotkv.com/commands/acl-load/index.md) | Write or read the ACL file |

`ACL DRYRUN` checks the rules without running anything, even for a user
that is `off`:

```
127.0.0.1:6379> ACL DRYRUN reports GET report:2026-09
OK
127.0.0.1:6379> ACL DRYRUN reports SET report:2026-09 x
"User reports has no permissions to run the 'set' command"
127.0.0.1:6379> ACL DRYRUN reports GET invoices:1
"User reports has no permissions to access the 'invoices:1' key"
```

A denied command fails with a `NOPERM` error:

```
127.0.0.1:6379> SET report:2026-09 x
(error) NOPERM User reports has no permissions to run the 'set' command
127.0.0.1:6379> GET invoices:1
(error) NOPERM No permissions to access a key
```

Commands run from scripts are checked as the calling user, and `EXEC` checks each queued command again.

## The ACL log

`ACL LOG` lists the most recent denied commands, keys and channels and
failed logins, newest first (10 by default, `ACL LOG 50` for more). Each
entry has `count`, `reason` (`command`, `key`, `channel` or `auth`),
`context` (`toplevel`, `multi` or `lua`), `object` (the command, key or
channel), `username`, `age-seconds`, `client-info`, `entry-id`,
`timestamp-created` and `timestamp-last-updated`. Repeats of the same
denial are counted in one entry. `ACL LOG RESET` clears it.

The log keeps `acllog-max-len` entries (default `128`). `INFO stats`
counts denials since startup as `acl_access_denied_auth`,
`acl_access_denied_cmd`, `acl_access_denied_key` and
`acl_access_denied_channel`.

## The ACL file

Users made with `ACL SETUSER` live in memory. To keep them across
restarts, set `aclfile`:

```
aclfile /var/lib/hotkv/users.acl
```

In `hotkv.toml` it is `aclfile` under `[security]`. The file holds one user
per line, in the form `ACL LIST` shows; blank lines and lines starting with
`#` are skipped:

```
# /var/lib/hotkv/users.acl
user default off
user admin on #<sha256-digest> ~* &* +@all
user app on #<sha256-digest> ~* &* +@all -@dangerous
user reports on #<sha256-digest> ~report:* resetchannels -@all +@read
```

- At startup HotKV loads the file after `requirepass`, so a `user default`
  line wins over `requirepass`; without one, `default` keeps the
  `requirepass` password. A missing file is not an error: the server
  starts with the default user. A file with an invalid line stops the
  start, naming the line.
- `ACL SAVE` writes every user to the file. It writes a new file and
  renames it into place, so the file is never half written. A new file is
  readable by its owner only, since it holds password digests.
- `ACL LOAD` replaces every user with the file's. If any line is invalid,
  nothing changes and the error names the line. Clients whose user no
  longer exists, or lost a channel they are subscribed to, are
  disconnected.

Both fail with an error when no `aclfile` is configured.

> **Caution**
> The packaged systemd service can write only to `/var/lib/hotkv`,
> `/var/log/hotkv` and `/run/hotkv`. Keep the ACL file in `/var/lib/hotkv`,
> or `ACL SAVE` fails.

Unlike Redis, HotKV does not take `user` lines in `hotkv.conf`: a `user`
directive stops the start. Keep users in the ACL file.

## Settings

| Setting | Default | Description |
| --- | --- | --- |
| `requirepass` | empty | Password of the `default` user |
| `aclfile` | empty | File `ACL SAVE` and `ACL LOAD` use, and that is loaded at startup |
| `acl-pubsub-default` | `resetchannels` | Channels a new user (or one `reset`) starts with: `resetchannels` none, `allchannels` every channel |
| `acllog-max-len` | `128` | Entries `ACL LOG` keeps |

In `hotkv.toml` they go under `[security]` with underscores
(`acl_pubsub_default`, `acllog_max_len`). `requirepass`,
`acl-pubsub-default` and `acllog-max-len` can be changed with `CONFIG SET`.

## Differences from Redis

- Users cannot be declared in the configuration file; use `aclfile`.
- `CONFIG GET requirepass` does not reveal the password.
- `skip-sanitize-payload` is accepted but `RESTORE` payloads are always
  checked.
- Categories are those listed above: HotKV adds `bloom`, `cms`, `topk` and
  `timeseries` and has no module categories.
- A TLS client certificate does not log a client in as a user; clients
  authenticate with `AUTH` or `HELLO`.
- Replicas authenticate their replication link with a shared password,
  not an ACL user (`masteruser` is accepted and ignored).

## Next steps

- [Security](https://docs.hotkv.com/security/index.md): TLS, protected mode, and the audit log.
- [ACL users in a cluster](https://docs.hotkv.com/clustering/production/index.md#an-acl-user-for-your-applications): users belong to one node, so create them on every node.
- [TLS](https://docs.hotkv.com/operate/tls/index.md): encrypt connections, including mutual TLS.