A Redis instance reaches the `maxmemory` limit configured in its config file, and the deployment never changed `maxmemory-policy` from its default. What happens to the commands clients send after that point, and what error do they see?
answer
- Default policy = noeviction
- OOM command not allowed > maxmemory
- denyoom flag: writes fail, reads pass
- maxmemory 0 = unlimited on 64-bit
- evicted_keys stays 0 under noeviction
basics
~20 sThe default policy is noeviction: Redis deletes nothing. Reads still work, but any command that would use more memory is rejected with an error starting "OOM command not allowed when used memory > 'maxmemory'". Keys with TTLs still expire normally.
solid answer
~50 s`maxmemory` caps the memory Redis reports as used for its dataset. When usage reaches the cap, Redis applies `maxmemory-policy`, whose default is **noeviction** — it evicts nothing. Under noeviction, commands flagged as memory-increasing (SET, LPUSH, HSET, INCR, SADD, and friends) fail with `-OOM command not allowed when used memory > 'maxmemory'`. Read commands (GET, LRANGE, EXISTS) and memory-freeing commands (DEL, UNLINK, EXPIRE, LPOP) still succeed, so the instance is not dead — it is read-only-ish. Keys with a TTL keep expiring, which may free enough room for writes to resume on their own, which is why the symptom often looks intermittent. The practical trap is that `maxmemory` defaults to 0 (unlimited) on 64-bit builds, so an unbounded instance never OOM-errors; it grows until the OS OOM-killer or swap ruins it. "Redis is a cache so it drops old data automatically" is false until you choose an eviction policy.
code
text · 9 lines127.0.0.1:6379> CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "noeviction"
127.0.0.1:6379> SET user:42 "payload"
(error) OOM command not allowed when used memory > 'maxmemory'.
127.0.0.1:6379> GET user:41
"still readable"
127.0.0.1:6379> DEL user:41
(integer) 1go deeper
Know that maxmemory sets a budget, that the default policy deletes nothing, and that writes then return an OOM error while reads keep working.
Explain the denyoom distinction, that TTL'd keys still expire so errors can come and go, and that maxmemory 0 means unlimited on 64-bit builds.
Triage from INFO memory/INFO stats, know RSS exceeds maxmemory because of fragmentation, buffers and fork copy-on-write, and pick the right remediation instead of blindly raising the limit.
Frame the default as a deliberate safety choice for mixed cache/system-of-record use, and set instance-level policy from what the data actually is — including whether that data belongs in this instance at all.
## What `maxmemory` is `maxmemory` is a configuration directive giving Redis a byte budget for the data it holds, e.g. `maxmemory 4gb`. It is a soft accounting limit, not an OS-enforced one: Redis compares its own `used_memory` figure against the limit before executing commands that can allocate. The accounting deliberately subtracts some transient buffers (replica output buffers, the AOF buffer), so the process RSS you see in `top` is normally **larger** than `maxmemory` — that gap matters when you size a container. On 64-bit builds the default is `maxmemory 0`, meaning "no limit". An instance with no limit cannot OOM-error; it simply keeps allocating until the kernel's OOM killer terminates it or the box starts swapping, at which point latency collapses because Redis touches memory on every command. Setting a limit is therefore the first production step, not an optimization. ## What happens at the limit When used memory reaches `maxmemory`, Redis consults `maxmemory-policy`. The default value is **noeviction**, which means: delete nothing, refuse to grow. Concretely, every command is tagged in the command table with a `denyoom` (use-memory) flag. Before executing a `denyoom` command while over the limit, Redis returns the error reply: `(error) OOM command not allowed when used memory > 'maxmemory'.` Commands without that flag run normally. So: - **Still works:** GET, MGET, EXISTS, LRANGE, HGETALL, TTL, SCAN, INFO, and all read paths. - **Still works:** DEL, UNLINK, LPOP, SPOP, EXPIRE, LTRIM — anything that frees or cannot grow memory. - **Fails:** SET, SETEX, INCR, LPUSH, HSET, SADD, ZADD, XADD, RPOPLPUSH's push side, and any script or MULTI containing them. Because TTL'd keys keep expiring in the background, memory can drop back under the limit on its own; writes then start succeeding again. Clients experience this as a flapping stream of OOM errors rather than a hard outage, which is why the condition is often misdiagnosed as a network or client-library bug. ## Why noeviction is the default Redis is used both as a cache and as a system of record for things like sessions, queues and dedupe sets. Silently deleting a user's session or a queued job to make room for a cache entry would be a data-loss bug, so the shipped default fails loudly instead. Choosing an eviction policy is an explicit statement that *everything in this instance is disposable* (`allkeys-*`) or that *only the keys I gave a TTL are disposable* (`volatile-*`). ## Diagnosing it `INFO memory` gives `used_memory`, `used_memory_rss`, `maxmemory`, `maxmemory_policy` and `mem_fragmentation_ratio`. `INFO stats` gives `evicted_keys` — under noeviction it stays at 0 no matter how bad things get, so a zero counter is not evidence of health. Client-side, count OOM errors: a well-behaved application should surface them as a distinct metric rather than as generic "redis error", because the remediation is completely different from a timeout. ## Fixing it There are only four real moves, in rough order of preference: 1. **Give the data TTLs** and switch to a `volatile-*` policy so genuinely disposable data is reclaimed. 2. **Declare the instance a pure cache** and switch to an `allkeys-*` policy. 3. **Shrink the data** — bad key design (giant hashes, unbounded lists, oversized serialized blobs) is usually the actual cause. 4. **Raise `maxmemory` / add nodes**, keeping headroom below the container limit for fragmentation, client buffers and fork copy-on-write during RDB/AOF-rewrite. Note that changing policy is live: `CONFIG SET maxmemory-policy allkeys-lru` takes effect immediately and Redis starts evicting on the next command that needs room — a useful emergency lever, but only if you are certain nothing in the keyspace is irreplaceable. Persist the change to the config file (or `CONFIG REWRITE`) or it vanishes on restart.
- Under noeviction and over the limit, which commands still succeed, and why?Every command carries a `denyoom` flag in Redis's command table marking it as potentially memory-increasing; only those are refused. Reads (GET, LRANGE, SCAN), introspection (INFO, TTL) and memory-freeing commands (DEL, UNLINK, LPOP, EXPIRE) lack the flag and run normally. That is why an over-limit instance behaves like a read-mostly store rather than being fully down, and why you can always DEL your way back under the limit.
- If `maxmemory` is left at its default of 0, what happens instead?Nothing inside Redis stops it: it keeps allocating until the operating system intervenes. On a container you get an OOM-kill and a hard restart with loss of anything not persisted; on a VM with swap enabled you get thrashing, because Redis randomly touches pages and every swapped page becomes a disk read on the command path, so p99 latency explodes. Always set an explicit limit below the container/VM memory, leaving headroom for RSS overhead and fork copy-on-write.
- Why does the process RSS exceed `maxmemory` even when Redis says it is under the limit?The maxmemory check uses Redis's own `used_memory` accounting, which excludes replica output buffers and the AOF buffer, and it cannot account for allocator fragmentation or the copy-on-write pages of a background save. So RSS is routinely 1.2–1.5x the configured limit, more during an RDB fork or a big rewrite. Size the container with that headroom, or the kernel will kill a process that believes it is within budget.
saying these in an interview costs you the question
- Saying Redis evicts old keys automatically by default — the default is noeviction.
- Claiming reads also fail with OOM; only memory-increasing commands are refused.
- Assuming Redis spills to disk or swaps data out when full — RDB/AOF are durability mechanisms, not overflow storage.
- Reading the OOM error as an operating-system OOM-kill; it is a Redis-generated error reply.
- Trusting `evicted_keys = 0` as proof memory is healthy under noeviction.