SSD Nodes Learn Hosting plans →
How to do am Matt ConnorBy Matt Connor · Updated 2026-08-29

How to Set Redis Object Cache for WordPress VPS

Make WordPress VPS requests cheaper with Redis: bind am to localhost, set maxmemory and eviction policy, then verify say the cache dey work for real.

Wetin Redis object cache dey do for WordPress

Redis object cache for WordPress dey store result of database queries for memory, so the next request go read dem from Redis instead of asking MySQL again. WordPress already get object cache for core, WP_Object_Cache, but e dey live for PHP memory and dem dey throw am away when request end. A drop-in file dey replace am with one wey dey talk to Redis, so cache fit survive from one request to the next.

Object caching no be page caching, and the difference determine whether this guide worth your time. Page cache dey store the finished HTML of one URL and serve am again without running PHP at all. That one faster pass anything Redis fit do, and e work for visitors wey no login. As person login, put item for cart, or open admin, page cache go step aside and WordPress go run the whole request: bootstrap, plugins, queries. Object cache dey make that request cheaper. Na the tool for traffic wey page cache no fit handle: logged-in sessions, carts, checkout, wp-admin. For WooCommerce shop, na most of the expensive traffic be that.

The two fit work together, and for busy site both belong. Make you clear about the problem wey you dey fix. Brochure site wey anonymous readers dey use dey get almost all its speed from page cache, and adding Redis to am no go change much.

Make we mention one honest limit before you start. Object cache no dey make slow query fast. E dey remove only the repeat of query wey don already run. The first request after cache miss go pay the full cost, so plugin wey dey run unindexed query still go run am once for every cache lifetime.

Wetín you need first

  • A Linux VPS wey get shell and sudo. You no need control panel.
  • WordPress wey PHP-FPM dey serve, for example for LAMP stack for Ubuntu 24.04.
  • WP-CLI for the machine. Every step here get equivalent for admin screen, but shell version dey faster.
  • Redis for the same machine wey PHP dey run. Low latency na the main reason, and network hop fit cancel the benefit.

Commands below na for Ubuntu 24.04 with PHP 8.3 and the www-data web user. Change the PHP version and user make dem match your machine. Run the wp commands from your WordPress directory, the one wey get wp-config.php.

Redis install and PHP extension

sudo apt update
sudo apt install -y redis-server php-redis
sudo systemctl enable --now redis-server
redis-cli ping

redis-cli ping suppose answer PONG. If e print Could not connect to Redis at 127.0.0.1:6379: Connection refused, e mean say server no dey run, so read systemctl status redis-server before you continue.

php-redis na PhpRedis, the C extension from PECL. E dey faster pass Predis, wey na pure PHP, and plugin go use am automatically when e dey available. PHP-FPM dey load extensions when e start, so new extension no go show until you restart the pool.

sudo systemctl restart php8.3-fpm
php -m | grep redis

Take care with that last check: php -m dey list modules for command line PHP, and FPM fit load different set. The check wey matter na the plugin own diagnostics, further down.

As of August 2026, Ubuntu 24.04 packages Redis 7.0.15, and this dey okay for object cache. If you want current release instead, Redis dey publish its own APT repository.

sudo apt install -y lsb-release curl gpg
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
sudo apt update
sudo apt install -y redis

If your distribution dey ship Valkey, the fork wey start after the 2024 licence change, e dey speak the same protocol and everything below still apply unchanged.

Bind Redis make nobody else fit reach am

Redis no get password by default. Anything wey fit open connection to port 6379 fit read every cached value and run FLUSHALL. Scanners fit find instances wey dey exposed to internet within hours, so configure the network setting before tuning.

Open /etc/redis/redis.conf and confirm these lines:

bind 127.0.0.1 -::1
protected-mode yes

Then check wetin really dey listen, because the config file na claim, while ss na the evidence.

sudo ss -lntp | grep 6379

127.0.0.1:6379 na wetin you want. 0.0.0.0:6379 mean Redis dey answer on the public interface: fix the bind line and restart.

When PHP and Redis dey for the same box, Unix socket better pass loopback TCP. TCP stack no dey for the path, and file permissions dey decide access instead of firewall rule wey you fit later change.

unixsocket /run/redis/redis-server.sock
unixsocketperm 770

The redis user and group own the socket, so the web user must join that group.

sudo systemctl restart redis-server
sudo usermod -aG redis www-data
sudo systemctl restart php8.3-fpm
redis-cli -s /run/redis/redis-server.sock ping

That one must also print PONG. Could not connect to Redis at /run/redis/redis-server.sock: Permission denied mean the group no take effect. Check id www-data, and remember say running PHP-FPM keep the groups wey e get when e start. Na why restart dey for the list. Leave TCP enabled until you prove say the socket dey work, otherwise typo fit remove both paths at once.

Redis suppose get how much memory?

Use your own server to calculate the number. Redis without maxmemory go continue grow until kernel memory finish and OOM killer terminate one process. Most times, na the biggest process, and for WordPress server, na often MySQL. journalctl -k | grep -i "out of memory" go show the kill after e don happen, but by then the site don go down.

Start with total RAM, then subtract the other needs. MySQL or MariaDB reserves innodb_buffer_pool_size plus buffers for each connection. PHP-FPM cost pm.max_children multiplied by the real resident size of one worker. For plugin-heavy site, this one commonly dey between 64 MB and 128 MB. Kernel and web server need some hundred megabytes. Wetin remain na your maximum, and Redis go take part of am.

Example budget for 4 GB VPS wey dey run one shop

These figures na examples, not measurements from your server. Replace each one with the value wey your server report.

  • MariaDB with 1 GB buffer pool: 1024 MB
  • PHP-FPM, 10 workers at 96 MB each: 960 MB
  • Kernel, nginx or Apache, sshd, logging: 512 MB
  • Wetin remain: roughly 1.5 GB

A maxmemory of 256 MB na sensible starting point for this setup. E leave enough headroom, and one WordPress site rarely need more.

Now measure instead of guessing. After one day of real traffic:

redis-cli info memory | grep -E 'used_memory_human|maxmemory_human|maxmemory_policy'
redis-cli dbsize

If used_memory_human dey far below your limit, reduce the limit and give the RAM back to MySQL, because MySQL go use am better. If e stay for the limit and evicted_keys dey rise throughout the day, increase the limit. Set the value for /etc/redis/redis.conf.

maxmemory 256mb
maxmemory-policy allkeys-lru

redis-cli config set maxmemory 256mb apply immediately, but e go disappear at the next restart. Na the same trap as bare sysctl -w. Edit the file, then sudo systemctl restart redis-server, then read the value again. E good to add a second limit: MemoryMax cap for the systemd unit go stop misconfigured Redis from taking down the whole server. Set am above maxmemory, never make e equal, because cgroup limit go terminate the process instead of evicting a key. If Redis dey run inside container beside WordPress, put the same figure inside the memory limits for your Compose file, and use the same reasoning when deciding whether to run the database in Docker or on the host.

Choose eviction policy with purpose

Fresh Redis dey default to noeviction. Check your own one:

redis-cli config get maxmemory-policy

Under noeviction, when instance full, e go stop accepting writes and answer with this:

(error) OOM command not allowed when used memory > 'maxmemory'.

That one line na the worst failure mode for this guide, because site no go go down. E go just slow down. Every cache write go fail, so WordPress go return to database to get the value, then try store am again for the next request and fail again. Site go now pay for all the original database work plus one round trip to Redis for every key. Nothing for WordPress admin go tell you say this dey happen. The string go show for PHP error log, so grep for OOM command not allowed when site slow down after you add cache.

allkeys-lru na the correct default here. Redis go drop the least recently used key when memory tight, and na exactly wetin object cache need, because every value inside am na copy of data wey still dey MySQL. Losing one key cost one query. Refusing one write cost every query, for every request, until somebody notice am.

Avoid volatile-* policies for this work. Dem only consider keys wey get expiry, and Redis documentation say dem behave like noeviction when no key get expiry. WordPress dey store most object cache entries without TTL, so volatile-lru for object cache fit fill up and start refusing writes. allkeys-lfu na fair alternative if your traffic dey hit small set of keys very often, because e dey evict by frequency instead of recency. Choose one intentionally and write down the reason.

Persistence: make e remain off unless you get reason

The packaged redis.conf dey enable RDB snapshots with lines like save 900 1, and e leave the append-only file off. For pure object cache, snapshots no dey give any benefit. By definition, you fit generate the data again, and cache wey you restore from file wey twenty minutes old na stale values wey WordPress go trust.

Snapshots still get cost. BGSAVE dey fork the process, and because of copy-on-write, memory use fit rise sharply while the child dey write. For small VPS, you go see am for Redis log:

Can't save in background: fork: Cannot allocate memory

and often this warning when startup dey happen. Redis dey tell you say the fork fit fail later:

WARNING overcommit_memory is set to 0! Background save may fail under low memory condition.

To turn snapshots off, set empty save schedule inside /etc/redis/redis.conf, restart, then confirm say the value come back empty.

save ""
sudo systemctl restart redis-server
redis-cli config get save

Keep persistence only if the same instance dey hold something wey you no fit rebuild, like job queue or rate-limit counters. If na so, split the two. Cache dey need keys wey fit evict, while durable data dey need keys wey remain. maxmemory plus eviction apply to the whole instance, no be to one database index. Two instances for two sockets na the clean answer.

Install the plugin, and understand the drop-in

wp plugin install redis-cache --activate
wp redis enable
wp redis status

wp redis enable dey print Object cache enabled. when e succeed. Wetin e really do na to copy wp-content/plugins/redis-cache/includes/object-cache.php go wp-content/object-cache.php. Na this copy be the drop-in, and na the drop-in dey do the work. WordPress dey load wp-content/object-cache.php very early, before any plugin code run. Na so the cache dey available for the whole request. Active plugin wey no get drop-in no dey cache anything.

The failure messages dey tell you which part fail. Object cache could not be enabled. mean say the copy fail, so wp-content no writable by the user wey dey run WP-CLI. A foreign object cache drop-in was found. mean say another caching plugin don already claim that filename, and the fix na wp redis update-dropin. If message end with Redis server is unreachable:, followed by the client error, connection settings no correct. Go back to redis-cli ping.

If permissions make the copy fail, put the file there by hand and give ownership to the web user.

cp wp-content/plugins/redis-cache/includes/object-cache.php wp-content/object-cache.php
sudo chown www-data:www-data wp-content/object-cache.php

Removing the plugin no dey remove the drop-in. Run wp redis disable first. E go print Object cache disabled. and delete the file. If you delete the plugin directory while the drop-in remain, the site go continue to run old cache code, but no plugin go dey update am.

Connection settings for wp-config.php

Add dem above the line wey dey read /* That's all, stop editing! */, because constants wey you define after am don too late.

define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_DATABASE', 0 );
define( 'WP_REDIS_PREFIX', 'shop_prod:' );

For Unix socket, set the scheme and the path. Dem go ignore host and port after that.

define( 'WP_REDIS_SCHEME', 'unix' );
define( 'WP_REDIS_PATH', '/run/redis/redis-server.sock' );
define( 'WP_REDIS_PREFIX', 'shop_prod:' );

WP_REDIS_MAXTTL dey force expiry for every key, for seconds. You no need am with allkeys-lru, and e useful if you want hard upper limit for how stale one cached value fit be.

One Redis, plenty sites: prefixes and databases

Redis dey give you sixteen numbered databases by default, and each one get one flat keyspace. If two WordPress installs point to database 0 without prefix, dem go write the same key names for the same space. One site fit then read the other site's options and serve dem. Give every site its own prefix.

define( 'WP_REDIS_PREFIX', 'shopA_prod:' );
define( 'WP_REDIS_DATABASE', 1 );

The prefix dey separate the key names. The database index dey separate the keyspaces. This matter when you flush one: if you empty one index, the others remain untouched. The plugin also document WP_REDIS_SELECTIVE_FLUSH. E go delete only the keys wey match your prefix instead of the whole database, but e need scan to find dem.

Prefixes and indexes no separate memory. maxmemory and the eviction policy apply to the whole instance. So, one busy site fit push another quiet site's keys out, and neither site go report am. Sites wey must not affect each other need separate Redis instances. Each instance go get its own socket and its own limit.

Make staging no join production cache

Staging site usually na copy of production files and database. This mean say e dey copy wp-config.php with the same prefix and database index. If you point am to the same Redis, e go write production keys with staging values. Test price or changed option fit then show for live site without any deploy or trace.

Set different salt for each environment by hand. For staging's wp-config.php:

define( 'WP_REDIS_PREFIX', 'shop_staging:' );
define( 'WP_REDIS_DATABASE', 5 );

Better still, give staging e own Redis instance, or no object cache at all. define( 'WP_REDIS_DISABLED', true ); go turn off the cache when e dey run and leave the drop-in in place. This na also the fastest way to confirm whether cache cause the bug or not.

Older tutorials use WP_CACHE_KEY_SALT for this. The plugin readme mark this constant as deprecated and say make you use WP_REDIS_PREFIX instead, so use the new name.

Verify am instead of just trust am

Start with the plugin diagnostics wey e get by itself.

wp redis status

The line wey matter pass na Drop-in. Drop-in: Valid mean say WordPress dey load this plugin file. Drop-in: Not installed mean say the copy never happen and the site no get persistent cache, no matter how green the admin screen look. Status dey report the connection, and Client dey name the extension wey dey use. Na there you confirm PhpRedis instead of Predis.

Then ask WordPress core directly, because e no care wetin the plugin dey think.

wp eval 'var_dump( wp_using_ext_object_cache() );'

bool(true) mean say core dey communicate with external object cache.

Then prove say keys dey enter, with the prefix wey you configure.

redis-cli -n 0 dbsize
redis-cli -n 0 --scan --pattern 'shop_prod:*' | head

dbsize wey dey increase as you click around the site na the proof. Zero keys with valid drop-in mean say the connection dey fail quietly, or the prefix no be the one wey you think.

Finally, check wetin Redis dey measure for you.

redis-cli info stats | grep -E 'keyspace_hits|keyspace_misses|evicted_keys|expired_keys'

The hit ratio na keyspace_hits / (keyspace_hits + keyspace_misses), and Redis documentation give that formula. Read am with two cautions. The counters cover the whole instance since the last restart, so dem mix every site and application wey dey share am. And the ratio immediately after flush or restart no mean anything, because the cache still dey fill. Make e run through one normal traffic day.

No compare your number with hit rate or query count wey hosting company publish. Those ones describe their sites and their plugin set. The figure wey matter na your own, measured before and after for a page wey page cache no fit serve.

curl -o /dev/null -s -w '%{time_starttransfer}\n' -b cookies.txt https://example.com/my-account/

Run am with logged-in cookie jar, several times, with cache off (WP_REDIS_DISABLED) and then on. That difference na your result.

When Redis dey make WordPress slower

A full instance with the wrong policy na the main one, as we cover above: OOM command not allowed when used memory > 'maxmemory'. for the log, and the site dey pay for both the database and the cache.

Redis for another host na the second one. WordPress dey make hundreds of object cache calls for one request. If one request make 500 calls and each round trip cost 1 ms, na half second of waiting be that wey local socket no go get. Keep Redis for the same box, or for private network wey get sub-millisecond latency. How much the same-box case gain from the kernel na separate matter: the cache aware scheduling wey Linux 7.2 add dey try keep processes like PHP-FPM and Redis wey dey chat plenty for cores wey share cache, and VPS guest no dey benefit from this as much as bare metal.

A huge autoloaded options table na the third one, and old sites dey get am often. WordPress dey cache all autoloaded options as one key, so one megabyte of dem dey cross the connection for every single request. Measure am:

wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024) AS kb FROM wp_options WHERE autoload IN ('yes','on','auto','auto-on');"

WordPress 6.6 add new autoload values, so older query wey match only 'yes' go under-report for modern install. Anything wey pass one megabyte na problem to fix for the options table, no be for Redis.

Restart dey empty everything, so the minutes after systemctl restart redis-server na all misses and all database work. Restart when traffic low. And object cache no dey stop wp-cron.php from firing when visitors load pages, and that one fit also cause slow requests: move WP-Cron go real system cron job while you dey handle this.

Housekeeping

After deploy wey change options or theme code, run wp cache flush to flush. Run wp redis update-dropin after plugin update if the drop-in no update by itself. A drop-in from old plugin version wey dey work against newer plugin fit cause strange behaviour. Monitor live server with redis-cli --stat; e dey print one line every second. redis-cli monitor dey print every command and e dey use real CPU for busy instance. Use am for few seconds while you reproduce the issue, then stop am.

One last number wey good to know: redis-cli info clients dey report connected_clients. PHP-FPM dey hold one connection for each worker, so that number suppose follow your pm.max_children. E no suppose pass am by one order of magnitude. If e do, something dey open connections and no dey close dem.

FAQ

I still need page cache if I dey run Redis object cache?

Yes, for anonymous traffic. Page cache dey serve stored HTML without running PHP, and this always cheaper pass running WordPress with warm object cache. Object cache dey handle requests wey page cache must skip: logged-in users, carts, checkout, and wp-admin. For shop or membership site, e good make you run both. For site wey visitors no dey ever log in, page cache dey do almost all the work.

How much memory I suppose give Redis for WordPress?

Calculate am from your own server instead of copying one figure. Take total RAM, subtract MySQL buffer pool and per-connection buffers, subtract pm.max_children multiplied by resident size of one PHP-FPM worker, then subtract some hundred megabytes for kernel and web server. Give Redis part of wetin remain, then check used_memory_human inside redis-cli info memory after one day of traffic and adjust am. One WordPress site usually dey settle for tens of megabytes, so 256 MB maxmemory na generous starting point for 4 GB server.

Why my site become slower after I enable Redis object cache?

The common cause na full instance wey dey use noeviction policy. Redis dey refuse new writes and return OOM command not allowed when used memory > 'maxmemory'., so WordPress fall back to database for every value and still waste time on Redis round trip. Check redis-cli config get maxmemory-policy, set allkeys-lru, and confirm say maxmemory no small. Other common causes na Redis server wey dey for remote host, where hundreds of round trips for each request dey add up, and multi-megabyte autoloaded options value wey crosses the connection for every request.

Several WordPress sites fit share one Redis server?

Dem fit, but you need take care. Give each site unique WP_REDIS_PREFIX so key names no go collide, and separate WP_REDIS_DATABASE index so flushing one site no go empty another one. Wetin dem still share na memory: maxmemory and eviction apply to the whole instance, so busy site fit evict quiet site's keys. Sites wey must not affect each other need separate Redis instances with their own limits.

E safe to delete wp-content/object-cache.php?

Yes. Na drop-in, e no be part of WordPress core, and removing am go return WordPress to the built-in per-request cache. Site go continue to work, but e go simply run more database queries. Prefer wp redis disable, wey go delete the file cleanly and report Object cache disabled.. Deleting am by hand na the correct emergency step if Redis dey down or misbehaving and you no fit reach the admin.