Databases & HA

Fix Redis OOM 'command not allowed when used memory > maxmemory' Errors

Diagnose and fix the Redis OOM maxmemory error on open-source Redis, Azure Cache for Redis and Azure Managed Redis by choosing the right eviction policy, TTLs and memory headroom.

11 min read
On this page

The Redis error OOM command not allowed when used memory > 'maxmemory' means memory use has reached the maxmemory limit and the eviction policy can't free anything, so Redis rejects writes while still serving reads. On self-managed Redis the usual cause is the default noeviction policy; on Azure Cache for Redis and Azure Managed Redis it is usually the default volatile-lru policy combined with keys that have no TTL. You fix it by choosing an eviction policy that matches how you use Redis (often allkeys-lru for a pure cache), giving cache keys expirations, removing oversized keys, and leaving memory headroom or scaling up.

Who this is for and what you will have at the end

This guide is for developers and operators who see the OOM error in application logs on open-source Redis, Azure Cache for Redis or Azure Managed Redis.

At the end you will have:

  • A clear diagnosis of why eviction isn't freeing memory.
  • An eviction policy chosen deliberately for your workload.
  • TTLs and key sizes under control.
  • Alerts that warn you before memory runs out again.

Why Redis returns the OOM error

When a client runs a command that adds data, Redis compares memory use with maxmemory. If it is over the limit, Redis evicts keys according to maxmemory-policy until it is back under. If the policy doesn't allow eviction, or there's nothing eligible to evict, commands that would use more memory fail with the OOM error and read-only commands continue to work.

The available policies:

PolicyWhat it evicts
noevictionNothing; returns an error on commands that add data
allkeys-lruLeast recently used keys, from all keys
allkeys-lfuLeast frequently used keys, from all keys
allkeys-randomRandom keys, from all keys
volatile-lruLeast recently used keys that have a TTL
volatile-lfuLeast frequently used keys that have a TTL
volatile-randomRandom keys that have a TTL
volatile-ttlKeys with a TTL, shortest remaining TTL first

Redis 8.6 also adds allkeys-lrm and volatile-lrm, which evict the least recently modified keys; check that your server version and managed service support them before relying on them.

The key rule: the volatile-* policies behave like noeviction if no keys have an expiration. That is the most common reason managed caches hit this error.

Defaults differ by platform

PlatformDefault maxmemory-policyHow maxmemory is set
Open-source Redisnoevictionmaxmemory in redis.conf or CONFIG SET; 0 means no limit on 64-bit systems
Azure Cache for Redis (Basic, Standard, Premium)volatile-lruCache size, minus reserved memory
Azure Managed Redisvolatile-lru (VolatileLRU in the CLI)SKU memory limit

An open-source server with maxmemory 0 won't produce this error at all; it keeps growing until the operating system runs out of memory instead.

Microsoft has announced a retirement timeline for all Azure Cache for Redis SKUs and recommends moving to Azure Managed Redis, so treat the Azure Cache for Redis steps below as a fix for existing caches rather than a reason to deploy new ones.

Prerequisites

  • redis-cli or another client that can run INFO, plus the host, port and credentials. Azure Managed Redis listens on port 10000 with TLS.
  • For Azure: write access to the cache resource (for example Contributor) and the Azure CLI. The az redisenterprise commands come from a CLI extension that installs on first use.
  • Knowledge of what the application stores: pure cache entries that can be rebuilt, or data that must not disappear, such as sessions, queues or locks.

Step 1: Confirm the memory state

Connect and read the memory, stats and keyspace sections:

# Azure Managed Redis
redis-cli -h contoso-cache.westeurope.redis.azure.net -p 10000 -a "<access-key>" --tls INFO memory
 
# Self-managed Redis
redis-cli -h redis01.contoso.com -p 6379 INFO memory
redis-cli -h redis01.contoso.com -p 6379 INFO stats
redis-cli -h redis01.contoso.com -p 6379 INFO keyspace

For Azure Cache for Redis Basic, Standard and Premium you can also run commands in the portal's Console, unless the cache uses a virtual network, Private Link, or has access keys disabled.

The fields that matter:

SectionFieldWhat it tells you
memoryused_memoryBytes allocated by Redis
memorymaxmemoryThe configured limit
memorymaxmemory_policyThe active eviction policy
memoryused_memory_rssMemory as seen by the operating system
memorymem_fragmentation_ratioRatio of used_memory_rss to used_memory, including other process overhead
memorymem_not_counted_for_evictReplica and AOF buffers, not counted for eviction
memoryused_memory_datasetBytes used by the data itself
statsevicted_keysKeys evicted because of maxmemory
statsexpired_keysKeys removed because their TTL ran out
statscurrent_eviction_exceeded_timeMilliseconds since used_memory last rose above maxmemory
keyspacedbN:keys=...,expires=...Total keys and how many have a TTL

INFO errorstats also counts errors by prefix, so a growing errorstat_OOM count confirms how often clients hit the limit.

Step 2: Work out why eviction isn't happening

Compare three things:

  1. Policy is noeviction. Eviction is disabled by design. Either change the policy or treat the instance as a store and add memory.
  2. Policy is volatile-* and expires is much lower than keys. Most keys have no TTL, so there's little or nothing to evict. If expires=0, the cache behaves exactly like noeviction.
  3. evicted_keys is rising but the error still appears. Eviction is working but can't keep up, or a single command adds a large amount of data at once. Redis documentation notes that a command that adds a lot of data, such as storing a big set intersection, can temporarily exceed the limit by a large amount. Look at big keys and write bursts.

Step 3: Choose the right eviction policy

Redis's own guidance, applied to common situations:

WorkloadRecommended policyWhy
Pure cache, a subset of keys is hotallkeys-lruGood default when you have no reason to prefer another
Pure cache, access frequency matters more than recencyallkeys-lfuKeeps keys that are used often
Pure cache, all keys accessed about equallyallkeys-randomCheap and fair
You can predict which keys are good candidates and give them short TTLsvolatile-ttlEvicts what is about to expire anyway
Same instance holds cache keys and keys that must persistvolatile-lru or volatile-lfuOnly TTL keys are evicted; every cache key needs a TTL
Data must never be evicted (queues, locks, primary data)noevictionWrites fail instead of silently losing data; size the instance accordingly

Redis recommends separate instances rather than mixing cache and persistent keys where possible. allkeys-lru is also slightly more memory-efficient than relying on TTLs, because an expiration costs memory per key.

For a semantic cache in front of an LLM, such as the one described in production LLMOps and enterprise RAG architecture, entries can always be regenerated, so allkeys-lru or allkeys-lfu with TTLs is usually the right fit.

Step 4: Change the policy

Self-managed Redis

Change it at runtime, then persist it:

redis-cli CONFIG SET maxmemory-policy allkeys-lru
redis-cli CONFIG GET maxmemory-policy
redis-cli CONFIG REWRITE

CONFIG REWRITE writes the running configuration back to the redis.conf the server was started with. Alternatively, edit redis.conf directly:

maxmemory 4gb
maxmemory-policy allkeys-lru

If the server has replicas or AOF persistence, set maxmemory below the physical RAM so the replication and AOF buffers (reported as mem_not_counted_for_evict) have room. Redis doesn't count those buffers against maxmemory, to avoid an eviction feedback loop.

Azure Cache for Redis

The CONFIG command is disabled; calling it returns an unknown command error. In the portal, open the cache, select Advanced settings, and change Maxmemory policy. With the Azure CLI:

az redis update \
  --name contoso-cache \
  --resource-group rg-cache-prod \
  --set "redisConfiguration.maxmemory-policy"="allkeys-lru"

Azure Managed Redis

The policy is a database property. Accepted values are AllKeysLFU, AllKeysLRU, AllKeysRandom, NoEviction, VolatileLFU, VolatileLRU, VolatileRandom and VolatileTTL:

az redisenterprise database update \
  --cluster-name contoso-cache \
  --resource-group rg-cache-prod \
  --eviction-policy AllKeysLRU

Step 5: Give cache keys an expiration

Even with an allkeys-* policy, TTLs keep memory under control proactively, and Microsoft notes that eviction under memory pressure adds server load. Set the TTL when you write:

redis-cli SET product:1001 '{"name":"Widget"}' EX 3600
redis-cli EXPIRE session:abc123 1800
redis-cli TTL product:1001

TTL returns the remaining seconds. Make TTLs part of the cache wrapper in your application rather than relying on each developer to remember them.

Step 6: Find and fix big keys

A few very large keys can consume most of the memory, defeat eviction and slow replication. Scan for them:

redis-cli --bigkeys
redis-cli --memkeys
redis-cli MEMORY USAGE product:catalog:all

--bigkeys and --memkeys scan the whole keyspace and report the biggest keys and average sizes per type; you can add -i 0.1 to sleep between batches on a busy server. MEMORY USAGE returns the bytes a single key consumes, including overhead.

Azure Managed Redis also exposes preview shard-level metrics that count large collections and strings per shard. Microsoft recommends keeping individual values under 512 KB for best performance; split large values across multiple keys, compress serialized values, and trim collections that grow without bound. On Flash Optimized tiers, large keys stay in RAM rather than moving to flash, which can cause OOM errors even when flash space is available.

Step 7: Leave headroom for fragmentation and replication

Azure Cache for Redis

Basic, Standard and Premium caches reserve memory with two settings under Advanced settings:

  • maxmemory-reserved: memory per instance in a cluster for non-cache operations such as replication during failover.
  • maxfragmentationmemory-reserved: memory reserved to absorb fragmentation.

Each defaults to about 10% of maxmemory, and both can be set between 10% and 60%. Raise them for write-heavy workloads or if you store values of 100 KB or more. Be careful on a full cache: raising the reservation lowers the memory available for data, and the cache evicts until both used_memory and used_memory_rss are below the new limit. Scaling via CLI, PowerShell or REST ignores reservation values in the same request; set them after the scale operation completes.

Azure Managed Redis

There are no reservation settings to tune. Watch Used Memory Percentage rather than Used Memory: with high availability enabled, Used Memory includes the replica and can look roughly twice the dataset size, while the percentage already accounts for the SKU limit. Microsoft suggests scaling to a larger size if Used Memory Percentage stays above 75%. Neither metric includes fragmentation.

Step 8: Monitor and alert

Create Azure Monitor alerts on:

  • Used Memory Percentage, so you can scale before the limit is reached.
  • Evicted Keys, to see when eviction starts and whether it is constant.
  • Cache Misses, because a jump after a policy change can mean the wrong keys are being evicted.

On Azure Managed Redis, rate-based metrics such as Evicted Keys now default to the Average aggregation; update older alerts that used Total. On self-managed Redis, collect used_memory, maxmemory, evicted_keys and the hit ratio, calculated as keyspace_hits / (keyspace_hits + keyspace_misses).

Verification

  • INFO memory shows the intended maxmemory_policy.
  • INFO keyspace shows expires close to keys for cache databases using a volatile policy.
  • Under load, evicted_keys rises while errorstat_OOM stays flat.
  • Application logs no longer show the OOM error, and the cache hit ratio is acceptable.
  • For queues, locks or other data that must persist, the instance is sized so that noeviction never triggers.

Troubleshooting

OOM command not allowed when used memory > 'maxmemory'. right after deploying a new Azure cache. The application writes keys without TTLs and the default volatile-lru has nothing to evict. Add TTLs or switch to allkeys-lru.

ERR unknown command 'CONFIG' on Azure Cache for Redis. CONFIG is blocked on the managed service, including through StackExchange.Redis IServer.ConfigSet. Use the portal or az redis update.

Errors continue after switching to an allkeys-* policy. Check for a few huge keys with --memkeys, and for commands that add large amounts of data in one operation. A single oversized write can exceed the limit before eviction catches up.

used_memory is below the limit but Azure Cache for Redis still evicts. used_memory_rss counts too. High fragmentation pushes RSS over the limit; raise maxfragmentationmemory-reserved and reduce large values.

Memory fills on only some shards. On clustered caches, hash tags or big keys can concentrate data on one shard. On Azure Managed Redis, split Shard Memory Used by Slots (Range) to find the imbalance.

Data you needed was evicted. You used an allkeys-* policy on an instance that also stores non-cache data. Move that data to a separate instance with noeviction, or switch to a volatile policy and give only cache keys TTLs.

Checklist

  • Root cause identified from maxmemory_policy, keys versus expires, and evicted_keys.
  • Eviction policy matches the workload; cache and persistent data separated where possible.
  • TTLs set by the cache layer for every rebuildable key.
  • Big keys found and split or compressed.
  • Headroom left for replication buffers and fragmentation.
  • Alerts on Used Memory Percentage and Evicted Keys, with a scaling plan.

References

Questions people ask

What does "OOM command not allowed when used memory > 'maxmemory'" mean?

Redis has reached its maxmemory limit and couldn't free memory under the configured eviction policy, so it rejects commands that would add data, such as SET and LPUSH. Read commands like GET keep working. It happens with the noeviction policy, or with a volatile policy when no keys have an expiration.

What is the default eviction policy on Azure Cache for Redis and Azure Managed Redis?

Both default to volatile-lru, which only evicts keys that have a TTL. If your application writes keys without an expiration, nothing is eligible for eviction and writes fail with the OOM error once memory is full. Open-source Redis defaults to noeviction.

Should I use allkeys-lru or volatile-lru?

Use allkeys-lru when Redis is purely a cache and every key can be rebuilt from a source of truth; Redis documentation calls it a good default. Use volatile-lru only when the same instance also holds keys that must never be evicted, and make sure every cache key has a TTL.

Can I run CONFIG SET maxmemory-policy on Azure Cache for Redis?

No. The CONFIG command is disabled on Azure Cache for Redis and returns an unknown command error. Change the policy in the portal under Advanced settings, or with az redis update. For Azure Managed Redis, use az redisenterprise database update with --eviction-policy.

RedisAzure Managed RedisAzure Cache for RedisCaching
  1. Migrate Azure Cache for Redis to Azure Managed Redis Before Retirement

    Azure Cache for Redis Basic, Standard and Premium retire on 30 September 2028. Size, create and cut over to Azure Managed Redis, including the new port, hostname and clustering changes.

    Databases & HA13 min read
  2. Azure SQL Database Backups: Point-in-Time Restore, LTR and Geo-Restore

    Set PITR retention and backup redundancy, add a long-term retention policy, and run point-in-time, deleted-database, LTR and geo-restores for Azure SQL Database and Managed Instance.

    Databases & HA13 min read
  3. Azure SQL Database vs Managed Instance vs SQL Server VM: How to Choose

    Compare Azure SQL Database, Azure SQL Managed Instance and SQL Server on Azure VMs on compatibility, high availability, limits, cost model and management, then pick one with a repeatable assessment.

    Databases & HA14 min read