Redis Cheatsheet
redis-cli and Debugging
Use this Redis reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Connecting
redis-cli # 127.0.0.1:6379 redis-cli -h cache.example.com -p 6380 redis-cli -h host -p 6379 -a "$REDIS_PASSWORD" -n 3 # -n selects the database redis-cli -u 'redis://user:pass@host:6379/0' # URI form redis-cli -u 'rediss://user:pass@host:6380/0' --tls # TLS redis-cli --tls --cacert ca.crt --cert client.crt --key client.key -h host -p 6380 redis-cli -c -h host # follow Cluster redirects redis-cli -3 # negotiate RESP3 (HELLO 3)
| Flag | Meaning |
|---|---|
-h -p | Host and port |
-a pass | Password, warns that it is visible in ps |
--user name | ACL username (6.0+) |
--pass pass | Same as -a, no warning |
--askpass | Prompt instead, the safe form for a shell |
-n db | Database number |
-u uri | redis:// or rediss:// |
--tls | TLS, with --cacert, --cert, --key, --sni |
-c | Follow MOVED and ASK in Cluster |
-3 / -2 | Force RESP3 or RESP2 |
-r n -i s | Repeat a command n times, every s seconds |
-t s | Connection timeout |
Prefer REDISCLI_AUTH or --askpass over -a, since a password on the command line lands
in ps output and shell history.
Output modes and scripting
redis-cli --raw GET hu:k # no quoting, no type prefixes, UTF-8 through redis-cli --no-raw LRANGE hu:l 0 -1 # force the pretty numbered form in a pipe redis-cli --json GET hu:json # JSON output redis-cli -x SET hu:blob < photo.bin # last argument from stdin redis-cli --quoted-input SET k "a\x00b" # accept escapes in the input redis-cli -r 5 -i 1 INFO clients | grep connected_clients redis-cli --eval script.lua key1 key2 , arg1 arg2 # note the SPACED comma
Three things that bite in scripts:
- Output is raw when stdout is not a tty and formatted when it is, so the same command
prints differently in a pipe. Pin it with --raw or --no-raw.
- --eval separates keys from args with a comma that must have spaces around it. numkeys
is inferred from how many precede it.
- -r -1 repeats forever, which with -i makes a poor man's monitoring loop.
Scanning and finding big keys
redis-cli --scan # every key, safely, via SCAN redis-cli --scan --pattern 'hu:session:*' redis-cli --scan --pattern 'hu:tmp:*' --count 1000 | xargs -L 100 redis-cli UNLINK redis-cli --bigkeys # biggest key per type, by element count redis-cli --memkeys # biggest key per type, by MEMORY USAGE bytes redis-cli --keystats # both at once, plus a size distribution redis-cli --hotkeys # most accessed keys, REQUIRES an LFU maxmemory-policy redis-cli --bigkeys --pattern 'hu:*'
| Tool | Answers | Cost |
|---|---|---|
--bigkeys | Which key has the most elements, per type | Full SCAN, one *LEN per key |
--memkeys | Which key uses the most bytes | Full SCAN, one MEMORY USAGE per key |
--keystats | Both, with a distribution histogram | Both of the above |
--hotkeys | Which keys are accessed most | Full SCAN plus OBJECT FREQ |
All of them do a complete SCAN, so they are safe to run against production but they do take
time and add load proportional to your keyspace. --hotkeys errors out unless
maxmemory-policy is allkeys-lfu or volatile-lfu, because it reads OBJECT FREQ.
Never use KEYS * for any of this. --scan exists precisely so you do not have to.
Latency
redis-cli --latency # min, max, avg over a rolling window redis-cli --latency-history -i 5 # a new sample line every 5 seconds redis-cli --latency-dist # a spectrum, needs a 256-color terminal redis-cli --latency-percentiles # p50, p99, p99.9 redis-cli --intrinsic-latency 10 # measures the KERNEL, not Redis
--latency measures round-trip PING time from where you run it, so it includes your
network. --intrinsic-latency runs a tight busy loop and reports the worst scheduling delay
the host kernel imposed, with no Redis involved. Run it on the Redis box itself: if it
reports 5ms, no amount of Redis tuning will get you below that, and you have a noisy
neighbour or a transparent-hugepage problem.
The server-side latency monitor is separate and off by default.
redis-cli CONFIG SET latency-monitor-threshold 100 # record events over 100ms redis-cli LATENCY LATEST # event, last time, last value, max value redis-cli LATENCY HISTORY command redis-cli LATENCY RESET redis-cli LATENCY DOCTOR # prose analysis of what it recorded redis-cli MEMORY DOCTOR # prose analysis of memory
LATENCY DOCTOR and MEMORY DOCTOR return human-readable advice, and both cheerfully tell
you they have nothing to say on a healthy or idle instance.
Slow queries
redis-cli CONFIG SET slowlog-log-slower-than 10000 # microseconds, 10000 = 10ms redis-cli CONFIG SET slowlog-max-len 256 redis-cli SLOWLOG GET 10 redis-cli SLOWLOG LEN redis-cli SLOWLOG RESET redis-cli SLOWLOG HELP
1) 1) (integer) 14 <- entry id 2) (integer) 1789531888 <- unix timestamp 3) (integer) 42311 <- microseconds of EXECUTION time 4) 1) "HGETALL" <- the command and its args, truncated 2) "hu:user:1042" 5) "127.0.0.1:61083" <- client address 6) "" <- client name, from CLIENT SETNAME
The duration is execution time only. It excludes time spent on the network and time the
command waited in the queue behind something else, so a client seeing 200ms while the slowlog
says 0.4ms means the delay is elsewhere: a slow neighbour command, a fork pause, or the
network. slowlog-log-slower-than 0 logs everything and -1 disables logging.
MONITOR
redis-cli MONITOR # 1789531888.747123 [0 127.0.0.1:61083] "HGETALL" "hu:user:1042" redis-cli MONITOR | grep -i flushall # what you are usually looking for redis-cli MONITOR | head -1000 > /tmp/trace.txt
MONITORstreams every command from every client to your connection. The documented cost is a large throughput hit, roughly 50 percent or worse on a busy server, and it can saturate your network link on its own. Use it for seconds at a time on production, never leave it attached, and never pipe it into something slow, because a slowMONITORconsumer fills its output buffer and gets disconnected.
It also shows plaintext arguments, so it leaks whatever your keys and values contain. The
lower-cost alternatives are INFO commandstats for aggregate command counts and SLOWLOG
for the outliers.
INFO
redis-cli INFO # every default section redis-cli INFO memory redis-cli INFO replication clients # several sections, 7.0+ redis-cli INFO commandstats redis-cli INFO latencystats # 7.0+ redis-cli INFO everything # including the expensive sections redis-cli CONFIG RESETSTAT # zero the counters
| Section | Watch |
|---|---|
server | redis_version, uptime_in_seconds, config_file |
clients | connected_clients, blocked_clients, client_recent_max_output_buffer |
memory | used_memory_human, used_memory_rss, mem_fragmentation_ratio, maxmemory_policy |
persistence | rdb_last_bgsave_status, aof_last_write_status, loading |
stats | instantaneous_ops_per_sec, keyspace_hits/misses, evicted_keys, expired_keys, rejected_connections |
replication | role, master_link_status, master_repl_offset, slave_repl_offset |
cpu | used_cpu_sys, used_cpu_user |
commandstats | cmdstat_<cmd>:calls, usec, usec_per_call, rejected_calls, failed_calls |
latencystats | Per-command p50, p99, p99.9 (7.0+) |
errorstats | Counts per error reply type (6.2+) |
keyspace | db0:keys=...,expires=...,avg_ttl=... |
# Cache hit rate redis-cli INFO stats | grep -E 'keyspace_(hits|misses)' # The three numbers that explain most incidents redis-cli INFO memory | grep -E 'used_memory_human|used_memory_peak_human|mem_fragmentation_ratio' redis-cli INFO stats | grep -E 'evicted_keys|expired_keys|rejected_connections' redis-cli INFO clients | grep -E 'connected_clients|blocked_clients'
mem_fragmentation_ratio is used_memory_rss / used_memory. Above about 1.5 means real
fragmentation, and activedefrag yes can reclaim it. Below 1.0 means Redis is swapping,
which is far worse than fragmentation and is an immediate incident.
Redis 8.0 adds INFO keysizes (a per-type size histogram) and a hotkeys section, so a
section name that is missing usually means an older server rather than a typo.
Clients
redis-cli CLIENT LIST # every connection, one line each redis-cli CLIENT LIST TYPE pubsub # normal | master | replica | pubsub redis-cli CLIENT INFO # just this connection redis-cli CLIENT ID redis-cli CLIENT SETNAME importer # shows up in CLIENT LIST and SLOWLOG redis-cli CLIENT KILL ID 42 redis-cli CLIENT KILL ADDR 10.0.0.9:51234 redis-cli CLIENT KILL LADDR 10.0.0.1:6379 TYPE normal SKIPME yes redis-cli CLIENT NO-EVICT on # 7.0+, exempt this client from eviction redis-cli CLIENT NO-TOUCH on # 7.2+, do not update LRU/LFU on my reads redis-cli CLIENT UNPAUSE redis-cli CLIENT PAUSE 5000 WRITE # stall writes, for a controlled failover
CLIENT LIST fields worth reading: age (connection lifetime), idle (seconds since the
last command), cmd (the last command run), multi (queued commands, -1 when not in a
transaction), sub/psub, and omem plus tot-net-out for output-buffer pressure. Always
CLIENT SETNAME from your app, because "which of these 400 connections is the importer" is
otherwise unanswerable.
CLIENT NO-TOUCH on is what a debugging session should set, so your own --bigkeys sweep
does not reshuffle the LRU ordering of production keys.
DEBUG and benchmarking
redis-cli DEBUG OBJECT hu:user:1042 # Value at:0x... refcount:1 encoding:listpack serializedlength:24 lru:... lru_seconds_idle:0 redis-cli DEBUG JMAP # no-op on most builds redis-cli DEBUG SLEEP 1 # block the server for 1 second, ON PURPOSE redis-cli DEBUG SET-ACTIVE-EXPIRE 0 # disable the expiry cycle, for tests redis-cli DEBUG QUICKLIST-PACKED-THRESHOLD 100
DEBUGis an unstable internal command set.DEBUG SLEEPblocks the whole server,DEBUG SEGFAULTcrashes it deliberately, andDEBUG SET-ACTIVE-EXPIRE 0breaks expiry until you set it back. Run these only against an instance you started yourself and can throw away.OBJECT ENCODINGplusMEMORY USAGEgive you the same useful information safely.
redis-benchmark -h host -p 6379 -q # quick summary of every test redis-benchmark -t get,set -n 100000 -c 50 -P 16 -q # ops, clients, pipeline depth redis-benchmark -t set -n 100000 -d 1024 -q # 1KB values redis-benchmark -n 10000 -r 100000 -t set -q # 100k random keyspace redis-benchmark -n 1000 script load "return 1" redis-benchmark --dbnum 9 -t set -n 1000 # keep it out of db 0
-P is the pipeline depth and it dominates the result, so a headline number quoted without
-P is meaningless. redis-benchmark writes keys (key:__rand_int__ and similar), so
point it at a throwaway instance or at least a spare --dbnum.
Backups and dumps
redis-cli --rdb /tmp/backup.rdb # ask the server for a fresh RDB, over the wire redis-cli --functions-rdb /tmp/funcs.rdb # only the function libraries redis-cli BGSAVE && redis-cli LASTSAVE # snapshot in place, confirm it advanced redis-cli DUMP hu:user:1042 | xxd | head -2 # one key, serialized redis-cli -h src DUMP hu:k # then RESTORE on the target redis-cli MIGRATE targethost 6379 hu:k 0 5000 COPY REPLACE # move one key live
--rdb is the remote-backup tool: it triggers a save and streams the file to your machine,
so it needs no filesystem access to the server. DUMP and RESTORE are per key and the
payload is version-checked, so a dump from a newer Redis may be rejected by an older one.
A triage order that works
1. INFO memory and INFO stats. Is it evicting, swapping, or fragmenting?
2. INFO clients. Are connections or blocked clients climbing?
3. SLOWLOG GET 20. Is one command family slow?
4. INFO commandstats sorted by usec_per_call. Which command dominates total time?
5. --bigkeys or --memkeys. Is one enormous key behind the O(n) commands?
6. --latency from a client host, then --intrinsic-latency on the server. Is it Redis, the
network, or the kernel?
7. INFO persistence. Did a fork or a failed save pause everything?
8. MONITOR for a few seconds, last, only if the above did not identify it.