WordPress Object Cache: Benchmarking Redis vs Memcached

by Sarah Mitchell
WordPress Object Cache: Benchmarking Redis vs Memcached

WordPress Object Cache: Benchmarking Redis vs Memcached

Every WordPress page load that skips a database query is a faster page load. Object caching is the mechanism that makes that skip possible, and for most sites running on managed WordPress hosting, the choice comes down to two backends: Redis and Memcached.

The problem is that most comparisons stop at "Redis supports persistence, Memcached doesn't" and call it done. That's a configuration fact, not a performance fact. What actually matters to a WordPress site owner is how each backend affects TTFB, how they behave under concurrent load, and whether the hosting plan you're already paying for even gives you access to either one.

I ran both backends through the same test pipeline I use for every host review on this site. Here's what the data shows.

The Metric That Makes Object Caching Worth Measuring

Before the results, the baseline problem. On a stock WordPress install with no object cache drop-in, every non-cached page request hits MySQL for options, transients, user data, and post metadata. On the 40-post test site I used for this benchmark, a single uncached page request generated 34 database queries averaging 187 ms TTFB (measured with curl -o /dev/null -s -w "%{time_starttransfer}" across 200 requests, median value).

That 187 ms is the number everything else is measured against.

The site ran on a single VPS (2 vCPU, 4 GB RAM, NVMe) with PHP 8.2 (PHP-FPM), Nginx, and MariaDB 10.11. I installed Redis 7.0 and Memcached 1.6 on the same host, isolated by port, and swapped the drop-in between runs without changing anything else. Each test ran three times; I used the median.

How I Configured Each Backend

Configuration matters as much as the software itself. A misconfigured Redis instance will lose to a well-tuned Memcached setup every time, so I documented both configs.

Redis 7.0 configuration (redis.conf excerpt)

  • maxmemory 256mb
  • maxmemory-policy allkeys-lru
  • save "" (persistence disabled to match Memcached's in-memory-only behavior)
  • tcp-backlog 511

WordPress Redis drop-in: Redis Object Cache plugin by Till Krüss, version 2.5.4, with WP_REDIS_SELECTIVE_FLUSH set to true in wp-config.php.

Memcached 1.6 configuration

  • -m 256 (256 MB memory cap)
  • -t 4 (4 threads)
  • Default slab settings

WordPress Memcached drop-in: the community object-cache.php maintained in the WordPress.org plugin directory, pinned to the version tagged 2023-11-01.

Both backends received a 10-minute warm-up period of 500 requests before measurements began, so the cache was fully populated.

Redis vs Memcached: Benchmark Results

All TTFB values are medians across 200 requests. Concurrency tests used ApacheBench (ab -n 1000 -c [level]). Query counts come from Query Monitor 3.16.0.

| Scenario | No Object Cache | Memcached 1.6 | Redis 7.0 | |---|---|---| | Single request, warm cache | 187 ms | 94 ms | 71 ms | | 10 concurrent users | 241 ms | 112 ms | 79 ms | | 50 concurrent users | 389 ms | 198 ms | 103 ms | | 100 concurrent users | 612 ms | 341 ms | 131 ms | | DB queries per request | 34 | 6 | 6 | | Memory used (warm cache) | — | 18.4 MB | 21.7 MB | | Cache hit rate (warm) | — | 94.1% | 97.3% |

The single-request TTFB gap between Memcached and Redis is 23 ms — noticeable but not dramatic. At 100 concurrent users the gap widens to 210 ms, and that's where the architectural difference becomes a real-world issue.

Both backends reduced database queries from 34 to 6 per request — identical, because the WordPress object cache layer itself determines what gets cached, not the backend. The performance difference comes from how each backend handles the retrieval of those cached objects under load.

Why Redis Pulls Ahead at Higher Concurrency

Memcached uses a multi-threaded architecture where each thread handles its own connections. Under low concurrency that's efficient. Under high concurrency, lock contention on shared memory slabs becomes a bottleneck. With 100 concurrent requests in my test, Memcached's TTFB climbed to 341 ms — still 44% faster than no cache, but nearly 3x slower than Redis at the same concurrency level.

Redis is single-threaded for command execution but uses an event loop (similar to Node.js) that handles thousands of concurrent connections without the locking overhead. That's why its TTFB at 100 concurrent users (131 ms) is only 84% higher than at a single user (71 ms), while Memcached's TTFB at 100 concurrent users (341 ms) is 262% higher than at a single user (94 ms).

For a site doing fewer than 20 concurrent users at peak, Memcached is a reasonable choice and often easier to provision on shared hosting. For anything above that — WooCommerce checkout spikes, editorial sites with traffic bursts — Redis holds up significantly better.

Cache Hit Rate: The Number Hosts Don't Advertise

The 97.3% Redis hit rate versus 94.1% for Memcached might look like a rounding difference, but at scale it compounds. On a site receiving 50,000 page views per day, a 3.2-point hit rate difference means roughly 1,600 additional database queries per day that Redis avoids and Memcached doesn't.

The hit rate gap comes from how each backend handles eviction. Memcached's slab-based memory allocator occasionally evicts a still-valid cache entry when a new object doesn't fit cleanly into an existing slab class. Redis's LRU eviction operates at the key level, so it evicts the least-recently-used key regardless of object size. For WordPress's mix of small option rows and larger post metadata arrays, Redis's approach produces fewer unnecessary evictions.

You can monitor Redis hit rate in real time with:

redis-cli info stats | grep -E "keyspace_hits|keyspace_misses"

For Memcached, the equivalent is:

echo "stats" | nc 127.0.0.1 11211 | grep -E "get_hits|get_misses"

Check these numbers 24 hours after enabling your object cache. If hit rate is below 85%, your maxmemory setting is probably too low.

Recommended Settings by Hosting Environment

Not every host gives you control over the object cache backend. Here's how to match the configuration to what's actually available.

Hosting Type Typically Available Recommended Config
Managed WP (Kinsta, Flywheel) Redis (managed) Use host's native Redis; skip third-party plugin
Managed WP (WP Engine) Memcached (internal) No config needed; enabled by default
Cloud VPS (DigitalOcean, Vultr) Your choice Redis 7+ with allkeys-lru, 256 MB min
cPanel shared hosting None or Memcached APCu object cache as fallback
Cloudways Redis (toggle in panel) Enable in panel; install Redis Object Cache plugin

On hosts that provide Redis natively (Kinsta, for example), skip the Redis Object Cache plugin and use the host's drop-in directly. Adding a plugin layer on top of a managed Redis integration adds function call overhead that partially offsets the cache benefit.

Do This First: A Four-Step Implementation Sequence

If you're enabling object caching for the first time, order of operations prevents the most common mistakes.

1. Confirm the backend is running before installing the drop-in.

For Redis: redis-cli ping should return PONG. For Memcached: echo "stats" | nc 127.0.0.1 11211 should return stats output. Installing the WordPress drop-in before the backend is running causes every object cache read to fail silently and fall back to the database — you get the overhead without the benefit.

2. Set maxmemory before the cache warms up.

If you skip this, Redis will use all available RAM and the OS will start swapping. 256 MB is a safe starting point for sites under 50,000 monthly visits. Increase to 512 MB if your hit rate is below 85% after 24 hours.

3. Measure TTFB before and after with a consistent method.

Use curl -o /dev/null -s -w "%{time_starttransfer}" https://yoursite.com from a non-local machine (a $4/month VPS in the same region works). Run it 20 times and take the median. Browser DevTools numbers include DNS and TCP overhead that makes before/after comparisons noisy.

4. Check Query Monitor the day after enabling caching.

Query Monitor 3.16.0 shows cached vs. uncached object requests per page. If you're still seeing more than 10 database queries on a standard post page, a plugin is bypassing the object cache — usually by calling $wpdb->query() directly instead of using the WP_Query or get_option APIs.

When Object Caching Isn't the Right Fix

Object caching reduces database query time. It doesn't fix slow PHP execution, unoptimized images, or render-blocking scripts. If your TTFB is above 600 ms with a warm object cache, the bottleneck is elsewhere.

A quick diagnostic: disable the object cache drop-in temporarily and re-run your TTFB test. If TTFB changes by less than 30 ms, database queries weren't your problem to begin with. In that case, profile PHP with Xdebug or Blackfire before assuming you need a faster host.

The other scenario where object caching adds complexity without proportional benefit is low-traffic sites (under 1,000 visits/day) on managed hosting where full-page caching is already in place. If Nginx or a CDN is serving cached HTML, the object cache only runs on cache misses — which may be infrequent enough that the operational overhead of maintaining Redis isn't justified.

Conclusion

Object caching for WordPress is not a toggle-and-forget optimization. The backend you choose, the memory limit you set, and the concurrency your site actually sees all determine whether you get a 50% TTFB reduction or a 62% one.

In controlled benchmarks on identical hardware, Redis 7.0 with allkeys-lru eviction outperformed Memcached 1.6 at every concurrency level tested — most significantly at 100 concurrent users, where Redis delivered 131 ms TTFB versus Memcached's 341 ms. For sites with predictable low traffic, Memcached remains a workable option, especially where Redis isn't available. For anything with traffic spikes or a WooCommerce component, the Redis numbers justify the slightly higher memory footprint.

Measure your baseline TTFB first. Enable the backend. Measure again. The data will tell you whether you're done or whether the bottleneck is somewhere else entirely.