WordPress Object Cache: Redis vs Memcached Benchmarked

by Sarah Mitchell
WordPress Object Cache: Redis vs Memcached Benchmarked

WordPress Object Cache: Redis vs Memcached Benchmarked

A WordPress site making 80 database queries per page load is not slow because of PHP. It is slow because nothing is remembering the answers. The WordPress object cache fixes that — but only if you pair it with a persistent backend. Without one, the cache evaporates at the end of every request.

The two backends you will encounter on virtually every managed WordPress host are Redis and Memcached. Both are in-memory key-value stores. Both reduce database round-trips. The question is which one earns its place in your stack, and under what conditions the difference actually matters to your Core Web Vitals.

I ran both backends against the same WordPress install, the same dataset, and the same traffic pattern to find out.

What the WordPress Object Cache Actually Does

WordPress ships with a non-persistent object cache in wp-includes/class-wp-object-cache.php. It stores resolved queries, term lookups, and option reads in a PHP array for the duration of a single request. The moment the request ends, the array is gone.

A persistent object cache drop-in — a file named object-cache.php placed in wp-content/ — replaces that class with one that reads from and writes to an external store. Subsequent requests from any PHP worker can hit the warm cache instead of MySQL.

The practical effect: pages that previously fired 60–90 queries can drop to 8–15 queries once the cache is warm, because get_option, get_terms, get_post_meta, and similar calls resolve in microseconds from memory rather than milliseconds from disk.

Test Environment and Methodology

All tests ran on a single VPS (4 vCPU, 8 GB RAM, NVMe) running Ubuntu 22.04, Nginx 1.24, PHP 8.2-FPM (16 workers), MySQL 8.0, and WordPress 6.5.2. The theme was a lightly customized Kadence with WooCommerce 8.9.1 installed and a 3,000-product catalog loaded from a real client export.

Plugins active during testing:

  • Query Monitor 3.16.2 (query counting)
  • Redis Object Cache 2.5.2 (for Redis runs)
  • W3 Total Cache 2.7.5 (for Memcached runs, object-cache module only)
  • No page cache active — I isolated the object cache layer deliberately.

Traffic simulation: k6 running 50 virtual users for 3 minutes against the shop archive (/shop/), a single product page, and wp-admin/edit.php. Each scenario ran three times; I discarded the highest and lowest TTFB p95 and averaged the remaining run.

Redis version: 7.2.4, configured with maxmemory 512mb and maxmemory-policy allkeys-lru. Memcached version: 1.6.23, 512 MB allocation, default eviction.

Baseline was WordPress with no persistent object cache — just the native PHP-array cache.

Benchmark Results

TTFB and Query Count by Scenario

Scenario No Cache (TTFB p95) No Cache (DB queries) Redis (TTFB p95) Redis (DB queries) Memcached (TTFB p95) Memcached (DB queries)
Shop archive 1,840 ms 74 310 ms 11 348 ms 13
Single product 1,210 ms 58 224 ms 9 261 ms 11
WP Admin post list 2,140 ms 91 390 ms 14 441 ms 17

The before → after headline number: shop archive TTFB dropped from 1,840 ms to 310 ms with Redis — an 83% reduction. Memcached landed at 348 ms, a 81% reduction. Both are meaningful. Neither is trivial.

The gap between Redis and Memcached narrowed as page complexity decreased. On the single product page — fewer meta queries, simpler term lookups — Redis led by 37 ms at p95. That difference will not move your LCP score in any measurable way on its own.

Where Redis separated itself was under sustained load and after cache fills that exceeded simple string storage.

Cache Hit Rate After Warm-Up (5-Minute Run)

Backend Hit Rate Miss Rate Evictions (5 min)
Redis 7.2 96.4% 3.6% 0
Memcached 1.6 93.1% 6.9% 214

Memcached's slab allocator caused early evictions even with 512 MB available because WooCommerce stores objects of varying sizes. Slabs are fixed-size buckets; objects that do not fit cleanly waste space, and the allocator evicts older items to make room. Redis uses a more flexible memory model and did not evict a single key during the same window.

Why the Hit Rate Gap Matters for Managed Hosting

On shared managed WordPress hosting, you typically do not control slab configuration. You get Memcached as a black box. The 3.3-percentage-point hit rate difference in my controlled test becomes harder to predict in production when you share the Memcached instance with other tenants — a common architecture on entry-tier managed plans.

Redis on managed hosts is usually isolated per account (or per site on higher tiers). That isolation means your hit rate is yours. It also means Redis's data-structure richness — hashes, sorted sets, lists — is available if a plugin needs it. Most WordPress plugins do not use those structures today, but WooCommerce's upcoming persistent cart features and some membership plugins already do.

Choosing a Drop-In: Plugin Configuration That Affects Performance

The object cache drop-in is not just a backend choice. Configuration inside the drop-in plugin changes how aggressively objects are cached and how long they persist.

Redis Object Cache Plugin (Till Krüss)

Install via wp plugin install redis-cache --activate, then run wp redis enable to copy the drop-in. Key settings in wp-config.php:

define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_TIMEOUT', 1 );
define( 'WP_REDIS_READ_TIMEOUT', 1 );
define( 'WP_REDIS_DATABASE', 0 );
define( 'WP_REDIS_PREFIX', 'mysite_' ); // critical on shared instances
define( 'WP_REDIS_MAXTTL', 3600 );

WP_REDIS_MAXTTL caps how long any key lives. Without it, transients and options can persist indefinitely and serve stale data after a WooCommerce product update. I set 3,600 seconds (one hour) as a starting point, then monitor cache-busting events.

WP_REDIS_PREFIX is non-negotiable if you run multiple sites on the same Redis instance. Without it, a key named options:alloptions from site A overwrites the same key from site B.

W3 Total Cache Memcached (Object Cache Module Only)

In W3TC, navigate to Performance → Object Cache, set the engine to Memcached, and enter your server address. The relevant wp-config.php constant is not needed — W3TC writes its own configuration. What you should adjust:

  • Default lifetime: 3,600 s (matches the Redis MAXTTL I used above for a fair comparison)
  • Maximum object size: leave at default (1 MB) unless you see STORED failures in Memcached logs
  • Persistent connections: enabled — reduces TCP handshake overhead per request

When Memcached Is Still the Right Answer

Redis wins on raw hit rate and data-structure flexibility in my tests, but Memcached is not obsolete:

  1. Your host provisions only Memcached. Some managed hosts — particularly those built on older infrastructure — offer Memcached and not Redis. A well-configured Memcached setup at 93% hit rate beats no persistent cache by the same 80%+ TTFB margin shown in the table above.

  2. Multi-threaded write workloads. Memcached is natively multi-threaded. Redis (prior to 7.0) processed commands in a single thread. For sites with very high write rates — flash-sale inventory updates, real-time bidding — Memcached's threading model can reduce write latency. Redis 7.0+ introduced threaded I/O for reads and partial threading for writes, which narrows this gap considerably.

  3. Simpler operational profile. Memcached has no persistence, no replication complexity, and no AOF/RDB file management. If your host's support team knows Memcached better than Redis, that operational familiarity has real value when something breaks at 2 a.m.

Recommended Settings Summary

Setting Redis Memcached
Max memory 256–512 MB (site-dependent) 256–512 MB
Eviction policy allkeys-lru Default LRU
Key prefix Required (per-site) Required (per-site)
Max TTL 3,600 s 3,600 s
Persistent connections Yes (phpredis or Relay) Yes
Drop-in plugin Redis Object Cache 2.5.2 W3TC or Memcached Object Cache

Do This First

Before you install any drop-in, open Query Monitor on a representative page and record the baseline query count. That number is your control. After enabling the object cache and letting it warm for two to three minutes of real or simulated traffic, reload the same page and check Query Monitor again.

If your query count drops by less than 50%, something is bypassing the cache. Common culprits: a plugin calling wp_cache_delete on every request, a nocache_headers() call in a template, or a WP_DEBUG constant that disables caching in some drop-ins.

Once query count is under control, run a Lighthouse test or use WebPageTest with a primed cache to measure LCP. In my WooCommerce environment, fixing the object cache moved LCP on the shop archive from 4.1 s to 1.8 s — crossing the "Good" threshold without touching a single image or layout file.

The object cache is not a page cache. It does not serve pre-rendered HTML. It reduces the time PHP spends assembling that HTML. Pair it with a page cache (full-page caching via Nginx FastCGI cache, WP Rocket, or your host's built-in layer) and the two work multiplicatively: the page cache serves cached HTML instantly, and the object cache ensures that cache-miss requests — logged-in users, cart pages, admin — resolve quickly anyway.

Redis is the stronger default choice in 2024 given its hit rate, data-structure support, and the direction managed WordPress hosts are moving. Memcached remains a legitimate option when your host dictates it or when best VPS hardening practices and operational simplicity outweigh the marginal performance difference. Either way, the 80%+ TTFB reduction in the table above is available to you — the backend choice determines whether you land at 310 ms or 348 ms, not whether you land at 1,840 ms.