Redis SCAN vs KEYS in production
Use SCAN, never KEYS, on a Redis instance that serves traffic. KEYS pattern inspects every key in the database in one command, and because Redis executes commands on a single thread, every other client waits until it finishes. SCAN returns a small batch and a cursor, so the work is split into many short calls.
SCAN has semantics that surprise people the first time: empty batches, duplicates and no snapshot. Below is how to read its output correctly, and how to make KEYS unavailable to the account you use for browsing.
Step 1: iterate with a cursor
Start at cursor 0 and keep calling with the cursor Redis returns until it comes back as 0:
> SCAN 0 MATCH session:* COUNT 100
1) "1792"
2) 1) "session:9f2c"
2) "session:41aa"
> SCAN 1792 MATCH session:* COUNT 100
1) "0"
2) 1) "session:07be"
The iteration is complete only when the returned cursor is "0". Getting an empty list does not mean you are done.
Step 2: understand COUNT and MATCH
COUNTis a hint for how much of the keyspace to walk per call, not how many keys to return. The default is 10.MATCHis applied after Redis picks the batch. With a selective pattern, most batches come back empty or nearly empty. That is normal; keep following the cursor.- On Redis 6.0 and later,
TYPEfilters by value type in the same way, for exampleSCAN 0 MATCH user:* COUNT 100 TYPE hash.
Raise COUNT (say 500–1000) if you are walking a large keyspace with a selective pattern and the round trips dominate. Keep it modest on a busy primary.
Step 3: handle duplicates and changes
SCAN guarantees that a key present for the whole iteration is returned at least once. It does not promise exactly once, and keys added or removed during the iteration may or may not appear. So:
- deduplicate in your code (a set is enough),
- treat the result as “roughly the keyspace at about this time”, not a snapshot,
- never use a SCAN result as the input to a destructive batch job without rechecking each key.
From the shell, redis-cli wraps the loop for you:
redis-cli -h cache.internal --scan --pattern 'session:*' | head
Step 4: inspect collections the same way
The same problem exists inside large values. HGETALL, SMEMBERS and LRANGE key 0 -1 on a key with millions of elements block just like KEYS. Use the incremental versions:
HSCAN user:42:prefs 0 COUNT 100
SSCAN online-users 0 COUNT 100
ZSCAN leaderboard 0 COUNT 100
LRANGE queue:emails 0 99
Check the size first with HLEN, SCARD, ZCARD or LLEN, then decide how much to read.
Step 5: take KEYS away from the browsing account
Rather than trusting everyone to remember, create an ACL user that cannot run KEYS or anything that writes. On Redis 6.2 and later:
ACL SETUSER inspector on >use-a-long-random-password ~* resetchannels -@all +@read -keys +scan +info +ping +dbsize
-@allstarts from nothing.+@readallows the read command category (GET,HGET,SCAN,TYPE,TTLand so on).-keysremovesKEYS, which is in the@readcategory.+info +ping +dbsizeadd a few server-level commands that browsing tools use.
Then confirm:
ACL GETUSER inspector
AUTH inspector use-a-long-random-password
KEYS *
(error) NOPERM …
Persist the user with ACL SAVE if you use an ACL file, or add it to redis.conf with the same rule string. Managed Redis services often have their own way to define users. Check your provider’s documentation.
Doing this in DevOpsPad
DevOpsPad’s Redis browser only uses SCAN. The key tree loads in batches of SCAN … COUNT 100, with an optional MATCH pattern and a Load more keys button. It keeps the cursor between batches and removes duplicate names from the display. It also reminds you that SCAN can return an empty batch before it reaches the end, so an empty page is not mistaken for an empty database. Collection previews use HSCAN, SSCAN and ZSCAN and show up to 100 entries, and string previews are capped at 64 KiB.
The query editor accepts an allowlist of read-only commands such as GET, MGET, TYPE, TTL, SCAN, HSCAN, HGET, LLEN, DBSIZE, INFO and PING. KEYS is not on the list. Replies above 8 MiB are rejected with a hint to use bounded ranges. Connecting as a named ACL user is supported, so the inspector account above works as-is.
See browsing keys with SCAN, read-only Redis commands and Redis ACL users and TLS, or the Redis connector overview.