WordPress Object Cache: Redis vs Memcached Benchmarked
Database queries are the most common reason a WordPress site slows down under load. Every uncached page request can fire 40–80 SQL queries; a product archive on WooCommerce can push that past 200. Object caching intercepts those repeated queries and serves the result from memory instead of MySQL.
Two tools dominate that layer: Redis and Memcached. Managed hosts market both, sometimes interchangeably, as if choosing one were a coin flip. It is not. The difference shows up in TTFB under concurrent load, in persistence behavior during a server restart, and in how cleanly each integrates with WordPress multisite.
This article benchmarks both backends on identical hardware, using the same WordPress installation, the same test data set, and the same load profile — so the numbers reflect the cache layer, not the server.
The Problem: What Uncached WordPress Actually Costs
Before touching any cache configuration, I measured baseline performance on a stock WordPress 6.5 install with WooCommerce 8.9, 2,000 products, and 5,000 orders. The host was a VPS with 4 vCPUs and 8 GB RAM (no managed cache layer enabled). I used k6 to simulate 50 concurrent virtual users over 3 minutes, hitting the shop archive, a product page, and the cart endpoint in rotation.
Baseline (no object cache):
| Metric | Value |
|---|---|
| Median TTFB | 610 ms |
| 95th-percentile TTFB | 1,340 ms |
| MySQL queries per page (shop) | 187 |
| Error rate (5xx) | 3.2% |
| PHP-FPM worker saturation | 94% |
At 50 VUs the site was already dropping requests. That 3.2% error rate came from PHP-FPM exhausting its worker pool while MySQL caught up. This is the baseline every hosting comparison should start from — not a single-user Pingdom test.
How I Set Up the Test Environment
Both cache backends ran on the same VPS, swapped in sequence with a full APCu and OPcache flush between runs so no warm-up advantage carried over.
Software versions:
- WordPress 6.5
- WooCommerce 8.9
- Redis 7.2.4 (via
redis-server) - Memcached 1.6.23 (via
memcacheddaemon) - Redis Object Cache plugin 2.5.4 (Tillman Ott)
- W3 Total Cache 2.7.5 (for Memcached integration)
- PHP 8.2.18, php-redis 6.0.2, php-memcached 3.2.0
Redis config (/etc/redis/redis.conf changes):
maxmemory 512mb
maxmemory-policy allkeys-lru
save ""
I disabled RDB persistence (save "") because the goal is a pure cache, not a data store. Persistence adds fsync overhead that skews latency numbers.
Memcached config:
-m 512
-t 4
512 MB RAM limit, 4 threads to match the vCPU count.
Load test parameters were identical for both runs: k6, 50 VUs, 3-minute sustained ramp, same URL rotation, same WooCommerce session cookie to simulate logged-in users (which bypasses full-page cache and forces object cache to do real work).
Redis vs Memcached: Benchmark Results
| Metric | No Cache | Memcached | Redis |
|---|---|---|---|
| Median TTFB | 610 ms | 148 ms | 74 ms |
| 95th-pct TTFB | 1,340 ms | 390 ms | 181 ms |
| MySQL queries / page (shop) | 187 | 51 | 12 |
| Error rate (5xx) | 3.2% | 0.4% | 0.0% |
| PHP-FPM worker saturation | 94% | 61% | 38% |
| Cache hit rate (steady state) | — | 79% | 94% |
| Memory used at steady state | — | 211 MB | 198 MB |
Redis cut median TTFB from 610 ms to 74 ms — a 88% reduction. Memcached got it to 148 ms, which is still a meaningful improvement over baseline, but Redis reached a 94% cache hit rate versus Memcached's 79%.
The hit-rate gap is the key data point. It explains almost everything else in the table.
Why Redis Outperformed Memcached in This Workload
Data structure support
WordPress stores some cache groups as serialized arrays. Redis can store those as native hashes, which means it can invalidate a single key within a group without flushing the entire group. Memcached treats every value as a flat byte string, so group-level invalidation requires either a namespace increment trick or a full group flush.
With WooCommerce, product meta, term relationships, and transients all live in overlapping cache groups. Every time a product is updated, Memcached's namespace increment effectively evicts a wide swath of related keys — that is why its hit rate was 15 percentage points lower.
Atomic operations and Lua scripting
The Redis Object Cache plugin uses MULTI/EXEC blocks to batch writes. Memcached has no native transaction equivalent; W3 Total Cache works around this with sequential set calls. Under 50 concurrent users, those sequential writes created contention visible as the 0.4% error rate.
Persistence as a feature, not a liability
I disabled persistence for this benchmark, but in production Redis persistence (AOF, not RDB) means a PHP-FPM restart or a server reboot does not cold-start the cache. Memcached is always in-memory only — every restart is a cold cache. On managed hosts that auto-restart services during maintenance windows, that difference can cause a brief but measurable traffic spike to MySQL.
Where Memcached Still Makes Sense
Memcached is not the wrong answer in every situation. It is the right answer in two specific cases:
-
Horizontal scaling with multiple web nodes. Memcached's multi-threaded architecture and simpler client libraries make it easier to share a single cache pool across a fleet of PHP nodes without a Redis Cluster setup. If you are running 10+ web servers and your host does not offer managed Redis Cluster, Memcached with consistent hashing is operationally simpler.
-
Hosts that offer Memcached but not Redis. Some shared and entry-level managed hosts (cPanel-based environments in particular) include Memcached as a standard add-on. A 79% hit rate with Memcached beats a 0% hit rate with no object cache. Use what is available.
Recommended Redis Configuration for WordPress
These are the settings I apply to every WordPress site that gets a Redis object cache. They are based on the benchmark environment above and validated across a 40-site agency portfolio.
wp-config.php constants
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_DATABASE', 0 );
define( 'WP_REDIS_TIMEOUT', 1 );
define( 'WP_REDIS_READ_TIMEOUT', 1 );
define( 'WP_REDIS_MAXTTL', 86400 ); // 24-hour ceiling on all keys
define( 'WP_REDIS_SELECTIVE_FLUSH', true ); // flush by prefix, not full FLUSHDB
define( 'WP_REDIS_IGNORED_GROUPS', ['counts', 'plugins'] );
WP_REDIS_SELECTIVE_FLUSH is the most important constant most tutorials skip. Without it, a plugin calling wp_cache_flush() wipes every key in the Redis database — including keys from other WordPress installs sharing the same Redis instance. With it, only keys prefixed to the current site are flushed.
WP_REDIS_IGNORED_GROUPS keeps transient counters (comment counts, post counts) out of Redis. Those values change on every write and generate more invalidation overhead than they save.
Redis maxmemory-policy choice
| Policy | Behavior | Use when |
|---|---|---|
allkeys-lru |
Evicts least-recently-used keys across all keyspace | General WordPress cache |
volatile-lru |
Evicts LRU keys that have a TTL set | Mixed cache + session store |
allkeys-lfu |
Evicts least-frequently-used keys | High-traffic sites with stable popular content |
noeviction |
Returns error when memory is full | Never use for WordPress cache |
For a dedicated WordPress object cache, allkeys-lru is the safest default. If you are also storing PHP sessions or WooCommerce session data in the same Redis instance, switch to volatile-lru and ensure session keys have a TTL.
Do This First: A Four-Step Rollout
Object cache changes are low-risk but not zero-risk. A misconfigured object-cache.php drop-in can silently serve stale data or, worse, cause a fatal error that takes the site down. This sequence minimizes that risk.
Step 1 — Verify Redis is running and reachable.
redis-cli ping
# Expected: PONG
redis-cli info memory | grep used_memory_human
If redis-cli is not available, the Redis server package is not installed — do not proceed.
Step 2 — Install the plugin without activating the drop-in.
Install Redis Object Cache 2.5.4 via the WordPress admin. Before clicking "Enable Object Cache" on the plugin's settings page, add the wp-config.php constants above. The drop-in (wp-content/object-cache.php) is not active until you click that button.
Step 3 — Enable on staging, run your load test.
Even a 5-minute k6 or Locust run at 10 VUs will confirm the hit rate is above 80% and that no 5xx errors appear. Check redis-cli info stats | grep keyspace_hits before and after.
Step 4 — Enable on production during low-traffic hours.
The cache warms within 2–3 minutes of real traffic. Monitor TTFB in your analytics or via a synthetic monitor for the first 15 minutes. If TTFB rises instead of falling, the drop-in is not connecting — check WP_REDIS_HOST and firewall rules before anything else.
How This Affects Managed Hosting Decisions
When evaluating managed WordPress hosts, the object cache tier is one of the most consequential specs — and one of the least prominently advertised. Here is what to look for:
- Redis version: Anything below 6.x lacks ACL support and some client-side caching features. Redis 7.x is the current stable branch.
- Dedicated vs shared Redis instance: A shared instance means other tenants'
FLUSHDBcalls can affect your cache. Ask explicitly. - Memory limit: 64 MB is common on entry plans. For a WooCommerce store with 1,000+ products, that fills within minutes and triggers constant eviction. 256 MB is a workable minimum; 512 MB is comfortable.
- Persistence policy: AOF persistence with
appendfsync everysecadds minimal latency and protects the cache across restarts. Hosts that disable persistence entirely are optimizing for their infrastructure cost, not your cache warm-up time.
A host that offers Redis 7.x, a dedicated instance with 512 MB, and AOF persistence will consistently outperform one offering Memcached on a shared pool — regardless of what their marketing page says about server hardware.
Conclusion
The WordPress object cache benchmark is clear: Redis delivered an 88% TTFB reduction (610 ms → 74 ms) and a 94% cache hit rate against an identical Memcached setup at 79%. The gap comes from Redis's native data structures, atomic batch writes, and group-level invalidation — all of which matter specifically to how WordPress organizes its cache groups.
Memcached remains a reasonable fallback when Redis is unavailable or when you are scaling across many web nodes without a managed Redis Cluster. In every other scenario, Redis with the configuration above is the object cache layer to deploy first.
If you are evaluating a managed WordPress host and object caching is not in the spec sheet, ask before you sign. The answer will tell you more about the host's performance architecture than any marketing benchmark they publish.