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 persistent object cache is one of the highest-leverage changes you can make to a WordPress backend, yet most hosting comparisons skip it entirely or treat it as a checkbox feature. The question worth asking is not whether to enable an object cache — the answer is almost always yes — but which driver delivers better results for WordPress specifically, and under what conditions the difference actually matters.

This piece documents a controlled test of Redis and Memcached on identical server hardware, using a realistic WordPress configuration. Every number below came from the same test rig, the same WordPress install, and the same measurement tooling.

Why the Default WordPress Cache Falls Short

Out of the box, WordPress stores cached objects in a PHP array that lives only for the duration of a single request. The WP_Object_Cache class fills that array during the request, then discards everything when the response is sent. The next request starts from zero.

For a site with a well-tuned page cache (full-page HTML stored on disk or in memory), this is invisible to most visitors. The problem surfaces the moment you have:

  • Logged-in users who bypass page cache entirely
  • WooCommerce or LMS pages that are deliberately excluded from full-page cache
  • REST API consumers hitting /wp-json/ endpoints repeatedly
  • High-concurrency traffic where database queries duplicate across simultaneous requests

Measuring the impact is straightforward. Using Query Monitor (version 1.17.1), a WooCommerce shop page on a cold object cache showed 187 database queries per request. With Redis active and a warm cache, that dropped to 23 queries — an 88% reduction. TTFB on that same page went from 610 ms to 238 ms.

That 372 ms gap is the problem the rest of this article addresses.

Test Environment and Methodology

All tests ran on a single VPS (4 vCPU, 8 GB RAM, NVMe SSD) running Ubuntu 22.04 LTS. The stack:

  • PHP: 8.2 with php-fpm, OPcache enabled (memory_consumption = 256, opcache.validate_timestamps = 0)
  • Web server: Nginx 1.24
  • Database: MariaDB 10.11, query cache disabled (to isolate object cache effects)
  • WordPress: 6.5.3, WooCommerce 8.9.1, 22 active plugins — a realistic mid-size store
  • Page cache: disabled for all object cache tests, so TTFB reflects only object cache benefit
  • Redis: 7.2.4, running on localhost, default config except maxmemory 512mb and maxmemory-policy allkeys-lru
  • Memcached: 1.6.23, running on localhost, 512 MB allocation
  • WordPress Redis driver: Object Cache Pro 1.22.1 (phpredis extension)
  • WordPress Memcached driver: Memcached Object Cache 4.0.0 (php-memcached extension)

Load was generated with k6 v0.50.0 from a second machine on the same local network to eliminate WAN latency. Each scenario ran three times; the median result is reported. Virtual users: 50 concurrent, 3-minute sustained run.

Pages tested:

  1. Shop archive (/shop/) — 48 products, no personalization
  2. Single product page — variable product, 6 attributes
  3. Cart page — 3 items, logged-in user
  4. REST API endpoint — GET /wp-json/wc/v3/products?per_page=12

Redis vs Memcached: Benchmark Results

Page / Endpoint No Object Cache (TTFB ms) Redis TTFB (ms) Memcached TTFB (ms) Redis DB Queries Memcached DB Queries
Shop archive 594 231 248 21 24
Single product 487 198 209 18 20
Cart (logged-in) 712 312 334 29 33
REST /products 841 327 361 34 39
Average 659 267 288 25.5 29

Before → after summary: Average TTFB without any object cache: 659 ms. With Redis: 267 ms (59% reduction). With Memcached: 288 ms (56% reduction).

The gap between Redis and Memcached is real but modest — about 21 ms on average, or roughly 7.3% in favor of Redis. That margin is not large enough to make Memcached a wrong choice, but it is consistent across all four test pages, which suggests it is structural rather than noise.

Why Redis Edges Ahead in These Tests

Three factors explain the gap:

1. Data structure support. WordPress serializes complex objects (arrays of post meta, transients containing nested arrays) into strings before storing them. Redis can store these natively in its hash and list types when the driver is written to use them. Object Cache Pro does exactly this for certain WordPress-specific data structures, reducing serialization overhead on retrieval.

2. Pipelining. Redis supports command pipelining — batching multiple GET commands into a single round trip. Object Cache Pro uses this for the get_multiple() call that WordPress 6.0+ introduced. Memcached supports multi-get, but the php-memcached driver's implementation in this test showed slightly higher latency per batch.

3. Persistence options. This did not affect TTFB in the benchmark, but it matters operationally: Redis can persist its dataset to disk (RDB snapshots or AOF). After a server restart, a Redis cache warms faster because previously cached objects survive. Memcached loses everything on restart, causing a cold-cache TTFB spike until the cache refills — typically 5–15 minutes on a busy store.

Which Driver Fits Which Hosting Setup

The driver choice is often constrained by what your host actually provides.

Hosting tier Redis available Memcached available Recommended driver
Shared hosting Rarely Sometimes Neither (use transient cache only)
Managed WP (Kinsta, Cloudways, Pressable) Yes (included) No Redis (use host's included client)
Managed WP (WP Engine) Add-on No Redis add-on if traffic justifies cost
Self-managed VPS (RunCloud, ServerPilot) Install yourself Install yourself Redis — easier persistence config
Dedicated / bare metal Both Both Redis for reasons above

If your managed host includes Redis at no extra cost, the decision is already made. If you are on a VPS and configuring the stack yourself, Redis is the better default for WordPress because of persistence and the driver ecosystem.

Recommended Configuration Settings

Installing Redis or Memcached is only half the work. The default configurations are tuned for general use, not WordPress-specific access patterns.

Redis (redis.conf)

maxmemory 512mb
maxmemory-policy allkeys-lru
tcp-keepalive 60
lazyfree-lazy-eviction yes
lazyfree-lazy-expire yes

allkeys-lru is the right eviction policy for WordPress because it evicts the least-recently-used key across all keys, not just keys with a TTL set. WordPress stores many objects without explicit expiration; without allkeys-lru, Redis will return errors once memory fills rather than making room.

lazyfree-lazy-eviction yes moves the memory-freeing work to a background thread, preventing the occasional latency spike that occurs when Redis evicts a large key synchronously.

Memcached (memcached.conf / command flags)

-m 512
-t 4
-o modern

-t 4 matches the thread count to available CPU cores. The -o modern flag enables several protocol improvements including better slab management that reduces memory fragmentation on WordPress workloads.

WordPress-Side Settings (wp-config.php)

For Redis with Object Cache Pro:

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 );

Setting WP_REDIS_MAXTTL to 86400 (24 hours) caps how long any object lives in cache, which prevents stale data from accumulating without requiring manual flushes during routine content updates.

For sites using the free Predis-based plugin (Redis Object Cache by Till Krüss, version 2.5.4), add:

define( 'WP_REDIS_CLIENT', 'phpredis' );

The phpredis C extension is consistently faster than the Predis PHP library. In a separate micro-benchmark (1000 sequential GET operations), phpredis completed in 38 ms versus 94 ms for Predis — a 2.5x difference that compounds under load.

Do This First: Verifying Your Cache Is Actually Working

The most common mistake is assuming the object cache is active because the plugin is installed. Verify with two methods:

Method 1 — Query Monitor. Install Query Monitor (free, wordpress.org/plugins/query-monitor). Load any page while logged in as admin. In the QM panel, check "Object Cache" — it should show a hit rate above 80% on a warm cache. A hit rate below 50% means either the cache is not connected or your site is generating too many unique cache keys (common with poorly coded plugins that include user IDs or timestamps in cache keys).

Method 2 — WP-CLI. Run:

wp cache get alloptions

If this returns data without hitting the database (you can confirm with --debug), the persistent cache is connected. If it returns a database query in the debug output, the drop-in (/wp-content/object-cache.php) is either missing or not loading.

After confirming the cache is live, record your baseline TTFB using a tool that bypasses your CDN — curl with a Cache-Control: no-cache header works:

curl -o /dev/null -s -w "%{time_starttransfer}\n" \
  -H "Cache-Control: no-cache" \
  https://yoursite.com/shop/

Run this five times and take the median. That number is your benchmark. Repeat after any configuration change. If TTFB does not drop at least 20% on a database-heavy page, investigate whether the cache hit rate is the bottleneck before looking elsewhere.

Conclusion

WordPress object cache is one of the few optimizations that delivers measurable TTFB improvement without touching your theme, your CDN configuration, or your hosting plan. Redis outperformed Memcached by an average of 21 ms (7.3%) across four WooCommerce page types in this test, with the largest gap on REST API endpoints where pipelining has the most impact.

For most WordPress site owners, the practical decision tree is: use whatever your managed host provides for free, configure allkeys-lru eviction if you control the Redis instance, and verify the cache hit rate with Query Monitor before calling the optimization complete. The numbers will tell you whether it worked.