Database Advanced

Troubleshooting Redis OOM: ‘command not allowed when used memory limit reached’ on Ubuntu 20.04 LTS

Resolve Redis 'OOM command not allowed' errors on Ubuntu 20.04 LTS. This guide covers root causes and step-by-step fixes for memory limit issues.

👨‍💻
Senior Systems Architect • Verified in Staging Labs

Resolve Redis 'OOM command not allowed' errors on Ubuntu 20.04 LTS. This guide covers root causes and step-by-step fixes for memory limit issues.

When your application relies on Redis for caching, session storage, or as a message broker, encountering the "OOM command not allowed when used memory limit reached" error can bring your services to a grinding halt. This critical error indicates that your Redis instance has hit its configured memory cap and can no longer accept write commands, leading to data loss, application slowdowns, and unresponsive user experiences. This guide will walk you through diagnosing and resolving this common Redis memory exhaustion issue on Ubuntu 20.04 LTS.

Symptom & Error Signature

Users will typically experience application failures, data not being saved or retrieved from cache, and general unresponsiveness. The specific error message will appear in Redis logs, application logs, and when attempting to execute write commands via redis-cli.

Typical Error Output:

  • From redis-cli when attempting a write operation:

    127.0.0.1:6379> SET mykey "hello"
    (error) OOM command not allowed when used memory > 'maxmemory'
    
  • In Redis server logs (e.g., /var/log/redis/redis-server.log or journalctl -u redis-server):

    12345:M 27 Sep 2026 10:00:01.234 # OOM command not allowed when used memory > 'maxmemory'
    
  • In application logs (example for a PHP application using Predis):

    [2026-09-27 10:00:01] app.CRITICAL: Redis connection error: OOM command not allowed when used memory > 'maxmemory' {"exception":"[object] (PredisClientException(code: 0): OOM command not allowed when used memory > 'maxmemory' at /var/www/html/vendor/predis/predis/src/Client.php:373)"}
    

Root Cause Analysis

This error primarily stems from Redis consuming more memory than allocated, and its maxmemory-policy being set to noeviction (the default) or another policy that doesn't allow immediate eviction.

Here's a breakdown of the common underlying causes:

  1. Redis maxmemory Limit Reached: The most direct cause. Redis is configured with a maxmemory directive in its configuration file (/etc/redis/redis.conf), and the total memory used by data (used_memory) has exceeded this limit. When maxmemory-policy is set to noeviction, Redis will block all write commands.
  2. Uncontrolled Data Growth: Your application is storing an increasing amount of data in Redis without proper expiration, leading to continuous memory consumption. This can include:
    • Session data without appropriate Time-To-Live (TTL).
    • Caching data that is never invalidated or evicted.
    • Accumulation of temporary keys.
  3. Inefficient Data Structures or Key Usage:
    • Storing large values or many individual keys instead of leveraging more memory-efficient data structures like Hashes, Sets, or Sorted Sets.
    • Lack of key expiration for transient data.
  4. Memory Leaks (Application or Redis): While less common for Redis itself, application-level logic errors might cause it to continuously create new keys or larger data structures without proper cleanup.
  5. Insufficient System RAM: Even if maxmemory is set, the underlying host might not have enough physical RAM to accommodate Redis and other services, leading to heavy swapping, performance degradation, or even the Linux OOM (Out Of Memory) killer terminating the Redis process.
  6. Snapshotting/Persistence Overhead (Forking): When Redis performs a background save (RDB) or AOF rewrite, it forks the main process. This child process shares memory with the parent but also uses Copy-On-Write (COW) memory, meaning any page modified by either process will be duplicated. For very large datasets, this temporary duplication can push total memory usage beyond the system's capacity or the configured maxmemory (if maxmemory is close to the physical RAM limit).
  7. Memory Fragmentation: Redis might report used_memory_rss (Resident Set Size – actual RAM used by the process) significantly higher than used_memory (memory used by the data itself). This indicates memory fragmentation, where the operating system has allocated more physical memory to Redis than is strictly necessary for its data, due to how memory pages are managed. A high mem_fragmentation_ratio (e.g., > 1.5) is a sign of this.

Step-by-Step Resolution

Addressing this error requires a methodical approach, starting with diagnosis and moving towards sustainable solutions.

1. Assess Current Redis Memory Usage & Configuration

First, connect to your Redis instance and gather information about its current state.

sudo redis-cli INFO memory

Look for these key metrics:

  • used_memory: The amount of memory Redis has allocated for your dataset.
  • used_memory_rss: The amount of physical memory (Resident Set Size) consumed by the Redis process.
  • mem_fragmentation_ratio: The ratio of used_memory_rss to used_memory. A ratio significantly above 1.0 (e.g., 1.5 or higher) indicates fragmentation.
  • maxmemory: The configured memory limit for Redis.
  • maxmemory_policy: The current eviction policy.

Also, verify your Redis configuration file:

grep -E "maxmemory|maxmemory-policy|activedefrag" /etc/redis/redis.conf

Finally, check your system's overall memory usage:

free -h

This will show available RAM and swap usage. High swap usage in conjunction with high used_memory_rss for Redis is a bad sign.

2. Implement or Adjust Key Expiration Policies

If keys are accumulating indefinitely, implement TTLs for your data.

  • Review Application Code: Identify where keys are being set without EXPIRE or SETEX.

  • Set TTLs: Ensure transient data (e.g., session tokens, temporary caches) has a reasonable expiration time.

    // PHP example with Predis
    $redis->setex('user:session:123', 3600, json_encode(['user_id' => 123, 'logged_in' => true])); // Expires in 1 hour
    $redis->expire('cache:product:456', 600); // Set expiry on an existing key to 10 minutes
    
    # Python example with redis-py
    r.setex('user:session:123', 3600, {'user_id': 123, 'logged_in': True})
    r.expire('cache:product:456', 600)
    

3. Configure maxmemory-policy

If your maxmemory-policy is noeviction, Redis will not automatically remove keys when the limit is reached, leading directly to the OOM error. Change this to an eviction policy suitable for your application.

Changing maxmemory-policy means Redis will start deleting keys when maxmemory is hit. Ensure your application can gracefully handle missing keys, as this effectively turns Redis into a volatile cache.

Edit your Redis configuration file, typically /etc/redis/redis.conf:

sudo vim /etc/redis/redis.conf

Find the maxmemory-policy directive. If it's commented out or set to noeviction, change it. For most caching scenarios, allkeys-lru (Least Recently Used across all keys) is a good starting point.

# maxmemory-policy noeviction
maxmemory-policy allkeys-lru

Other common policies include:

  • volatile-lru: Evict LRU keys that have an expire set.
  • allkeys-random: Evict random keys.
  • volatile-ttl: Evict keys with the shortest TTL.

After modifying, restart the Redis service:

sudo systemctl restart redis-server

4. Increase maxmemory (Use with Caution)

If your application legitimately requires more memory, and your server has sufficient free RAM, you can increase the maxmemory limit.

Blindly increasing maxmemory without understanding the root cause or verifying available system RAM can lead to your entire server running out of memory. This can cause the Linux OOM killer to terminate critical processes (including Redis or even the OS itself) or heavy swapping, severely degrading performance. Only increase if your host has ample free RAM.

Edit /etc/redis/redis.conf:

sudo vim /etc/redis/redis.conf

Locate the maxmemory directive and adjust its value. For example, to set it to 512 MB:

maxmemory 512mb

Save and restart Redis:

sudo systemctl restart redis-server

5. Optimize Data Structures and Key Usage

Review your application's use of Redis.

  • Hashes for Related Data: Instead of storing multiple individual keys for an object (user:1:name, user:1:email), use a single Hash key (user:1 with fields name and email). This is often more memory-efficient.
  • Sets/Sorted Sets: For collections of unique items or items with scores, these are highly optimized.
  • BITSET/BITCOUNT: For boolean flags or presence tracking, these can be extremely space-efficient.
  • Avoid Large Keys/Values: Break down very large values into smaller chunks or consider storing them outside Redis (e.g., in an object storage) and just keeping references in Redis.
  • JSON vs. Native Redis Types: While JSON is convenient, storing complex objects directly as JSON strings can be less efficient than using Redis's native HASH or LIST types.

6. Address Memory Fragmentation

If your mem_fragmentation_ratio is consistently high (e.g., 1.5 or more), Redis is using more physical RAM than its data requires.

  • Restart Redis: A simple restart can temporarily clear fragmentation, as the OS reclaims and reallocates memory. This is a temporary fix.

    sudo systemctl restart redis-server
    
  • Enable Active Defragmentation (Redis 4.0+): Redis can actively defragment memory in the background with minimal performance impact.

    Edit /etc/redis/redis.conf:

    sudo vim /etc/redis/redis.conf
    

    Add or uncomment these lines:

    activedefrag yes
    # The minimum percentage of fragmentation to start defragging
    active-defrag-threshold-lower 10
    # The maximum percentage of fragmentation to stop defragging
    active-defrag-threshold-upper 100
    # Minimal amount of AIL (Active Incremental Defragmentation) work per cycle.
    active-defrag-cycle-min 1
    # Maximal amount of AIL work per cycle.
    active-defrag-cycle-max 25
    

    Active defragmentation consumes some CPU cycles, but it's generally a good trade-off for long-running instances to prevent memory waste.

    Restart Redis for changes to take effect:

    sudo systemctl restart redis-server
    

7. Scale Your Redis Instance

If you've optimized everything and still hit memory limits, it's time to consider scaling.

  • Vertical Scaling (Upgrade Server): If your current server is undersized, upgrading to a VM or physical server with more RAM is the simplest solution.
  • Horizontal Scaling (Redis Cluster/Sharding): For very large datasets or high throughput, consider deploying Redis Cluster. This allows you to distribute your data across multiple Redis nodes, effectively increasing your total memory capacity and improving performance. This requires significant architectural changes to your application.
  • Managed Redis Service: For production environments, consider migrating to a managed Redis service (e.g., AWS ElastiCache, Google Cloud Memorystore, Azure Cache for Redis). These services offer easier scaling, high availability, and reduced operational overhead.

8. Monitor Redis and System Resources Continuously

To prevent future OOM issues, set up robust monitoring.

  • Redis Metrics: Track used_memory, maxmemory, mem_fragmentation_ratio, keyspace metrics, and evicted_keys (if an eviction policy is in place).
  • System Metrics: Monitor overall CPU, RAM, and swap usage on the host.
  • Alerting: Configure alerts to notify you when Redis memory usage approaches its maxmemory limit or when system RAM is low.
  • Tools: Use monitoring stacks like Prometheus + Grafana, Netdata, Datadog, or New Relic to visualize and alert on these metrics.

By systematically applying these steps, you can diagnose and resolve the "Redis OOM command not allowed" error, ensuring the stability and performance of your applications.

👨‍💻

Johnathon Wheeler

Senior Systems Architect & DevOps Engineer • Austin, TX

Connect on LinkedIn →

Johnathon has over 16 years of hands-on experience designing, debugging, and scaling Linux web hosting stacks, container clusters, and high-availability database architectures. Every guide on ButItWorkedLocal is independently tested against Debian 12, Ubuntu 24.04/22.04 LTS, Rocky Linux, and Docker environments to guarantee reproducibility in production.

🛡️

Our Production Verification Guarantee

Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.