# Many WordPress Sites, One OPcache: Why wp-admin Gets Slow and How to Fix It

> OPcache settings for multiple WordPress sites: why sites on one PHP version share one cache, how to read the hit rate, and how to size memory and file limits.

The right **OPcache settings for multiple WordPress sites** start from one fact: on Nginx servers, every site on the same PHP version shares one OPcache. With PHP's defaults (128 MB, 10,000 files) a server with only a few busy sites can fill it, PHP recompiles code, and wp-admin turns slow. Here is how to measure and size it.

You moved your sites from shared hosting to your own server to make them faster. The front end flies, thanks to the page cache. Then you log in, and the **WordPress dashboard feels slower than it did on cheap shared hosting**. Saving a post drags, the plugins page takes seconds.

The cause is often not the database or a heavy plugin. It is a PHP cache that every site on the server fights over. If you have read our guide on [**PHP workers**](/php-workers-and-why-do-you-need-them/), this is the other half of the PHP story: workers decide how many requests run at once, OPcache decides how much work each request repeats.

This guide shows how OPcache is shared, how to read its numbers, how to size it for many sites, and how it works on xCloud.

![One OPcache per PHP version: ten sites share the PHP 8.3 cache while a busy store has its own PHP 8.2 cache](/_landing/blog/opcache-settings-for-multiple-wordpress-sites-image-1.png)

## TL;DR

Short on time? Here is the whole guide in a few lines:

- **OPcache is shared per PHP version, not per site.** On Nginx servers, all sites on PHP 8.3 use one cache in memory with one file limit.
- **PHP's defaults are small for many sites:** 128 MB of memory and 10,000 cached files, set in the [PHP OPcache configuration](https://www.php.net/manual/en/opcache.configuration.php).
- **A full cache hurts wp-admin first,** because logged-in pages skip the page cache and always run PHP.
- **Measure before you change anything:** hit rate, free memory, cached keys against the limit, and the restart counters.
- **Raise one setting at a time:** memory when memory is full, Max Accelerated Files when the file limit is full.
- **On Nginx servers, a busy site can get its own cache** by moving it to a PHP version no other site uses, at the cost of more RAM.
- **On xCloud,** OPcache is on for every PHP version, starts at 512 MB and 100,000 files, and is changed per PHP version from the dashboard.

## The Finding: One Settings Change Touches Every Site on That PHP Version

Most OPcache tutorials tune one site. On a server with many sites, that framing is wrong.

In xCloud's own code, the OPcache settings screen you open from one site's settings writes the values to that **PHP version's** configuration file. On Nginx servers it then restarts PHP for that version; on OpenLiteSpeed servers it restarts the whole web server. So the change applies to every site on the server that runs the same version, and on Nginx servers they all share one cache in memory. The settings popup says so: it shows **'OPcache settings for PHP 8.3'**, not the site's name.

![The Manage OPcache Configurations popup in xCloud shows the PHP version the settings apply to](/_landing/docs/control-opcache-with-xcloud-image-3.png)

This is how it usually goes wrong: each site is fine on its own, but together their code no longer fits in the cache that PHP version shares.

## Why Many Sites Slow Down wp-admin

**OPcache** keeps compiled PHP code in memory, so PHP does not read and compile the same files on every request. Think of it as a shared kitchen fridge: it works great until ten flatmates fill it, and then someone's food gets thrown out every day.

### How the cache gets shared

PHP gives OPcache one block of shared memory when its service starts. Every PHP process started by that service reads from the same block. On a typical server, each PHP version runs its own service, so each version gets its own cache.

Ten WordPress sites on PHP 8.3 therefore put all their PHP files into one cache. A site with WooCommerce, a page builder and a few dozen plugins can load thousands of PHP files on its own.

### What happens when it fills up

Two limits can run out:

- **Memory (`opcache.memory_consumption`).** When there is no free memory, new files are not cached. If too much memory is also wasted on old copies of changed files, OPcache schedules a restart and clears the whole cache. [PHP's reference](https://www.php.net/manual/en/opcache.configuration.php) sets the wasted-memory threshold with `opcache.max_wasted_percentage` (default 5%).
- **Files (`opcache.max_accelerated_files`).** Once OPcache has stored as many files as the limit allows, new files are not cached, and PHP compiles them again on every request.

### Why the admin feels it first

Visitors mostly get pages from the page cache, so PHP barely runs for them. Logged-in admin pages skip the page cache and always run PHP. They also load admin code that front-end visitors never touch, which is exactly the code that drops out of a crowded cache.

The result: the shop looks fast to customers, while you wait on every click in the dashboard.

## Measure It: Hit Rate, Memory, Keys and Restarts

Do not guess. PHP's [`opcache_get_status()`](https://www.php.net/manual/en/function.opcache-get-status.php) function returns every number you need.

**Check it from the web server, not the command line.** PHP on the command line has its own OPcache, and `opcache.enable_cli` is 0 by default, so `php -r` shows nothing about your sites.

Create a file with a hard-to-guess name, for example `opcache-check-7f3k2.php`, in one site's web root:

```php
<?php
header('Content-Type: text/plain');
$s = opcache_get_status(false);
if (!$s) { exit("OPcache is off for this PHP version\n"); }
$m = $s['memory_usage'];
$st = $s['opcache_statistics'];
$i = $s['interned_strings_usage'];
printf("Hit rate: %.1f%%\n", $st['opcache_hit_rate']);
printf("Memory used: %d MB, free: %d MB, wasted: %.1f%%\n", $m['used_memory'] / 1048576, $m['free_memory'] / 1048576, $m['current_wasted_percentage']);
printf("Interned strings free: %d MB\n", $i['free_memory'] / 1048576);
printf("Cache full: %s\n", $s['cache_full'] ? 'yes' : 'no');
printf("Cached keys: %d of %d\n", $st['num_cached_keys'], $st['max_cached_keys']);
printf("Restarts (memory full): %d\n", $st['oom_restarts']);
printf("Restarts (file limit full): %d\n", $st['hash_restarts']);
```

Open it in your browser, read the numbers, then **delete the file**. It shows server details that should not stay public.

Because every site on that PHP version shares the cache, one file on one site tells you about all of them.

### Read the result

| What you see | What it means | What to change |
|---|---|---|
| Free memory near 0, **Cache full: yes**, or memory restarts above 0 | Not enough room for the code of all sites on this PHP version | Raise `opcache.memory_consumption` |
| Cached keys close to the limit, or file-limit restarts above 0 | Too many PHP files for the limit | Raise `opcache.max_accelerated_files` |
| Interned strings free memory near 0 | Repeated names (classes, functions) no longer fit | Raise `opcache.interned_strings_buffer` |
| Hit rate close to 100%, nothing full, no restarts | OPcache is not your problem | Look at the database, PHP workers or a slow plugin |

![Decision chart: read the OPcache numbers, then raise memory, the file limit or the interned strings buffer](/_landing/blog/opcache-settings-for-multiple-wordpress-sites-image-2.png)

The counters start from zero after every PHP restart. Read them after the sites have had normal traffic for a few hours, ideally after a day.

## Size OPcache for N Sites

There is no honest "X MB per site" number. A blog with five plugins and a WooCommerce store with fifty load very different amounts of code. So size from your own numbers.

### Step 1: Count the PHP files

Run this over SSH or in the [**web terminal**](/docs/access-web-terminal-in-xcloud/) for each site, and add the results up for every site on the same PHP version:

```bash
find /var/www/example.com -type f -name '*.php' | wc -l
```

Use your own site path. Not every file is loaded on every request, so this count is a safe upper bound.

### Step 2: Compare the total with the file limit

PHP rounds `opcache.max_accelerated_files` up to the next number in a fixed list of primes, so 10,000 becomes 16,229 and 100,000 becomes 130,987 (from the [PHP reference](https://www.php.net/manual/en/opcache.configuration.php)). The allowed range is 200 to 1,000,000.

Here is the arithmetic for an example server where each site has about 6,000 PHP files. Swap in your own count.

| Sites on one PHP version | PHP files (example: 6,000 each) | PHP default limit (16,229 keys) | xCloud default limit (130,987 keys) |
|---|---|---|---|
| 1 | 6,000 | Fits | Fits |
| 3 | 18,000 | Full | Fits |
| 10 | 60,000 | Full | Fits |
| 20 | 120,000 | Full | Tight: watch cached keys |
| 30 | 180,000 | Full | Full: raise the limit or split versions |

The file limit is cheap to raise. Memory is what actually costs you RAM.

### Step 3: Set memory, then check free memory

Start with a generous `opcache.memory_consumption`, let the sites warm up, and read free memory again. A good place to land is a cache that never reports **Cache full** and still has some free memory after a busy day.

If a large share stays free for days, you can lower it and give the RAM back to PHP workers and the database. Treat this as a starting point rather than a strict rule.

### Step 4: Change one setting at a time

Raise either memory or the file limit, never both blindly. Then wait, and read the numbers again. Otherwise you cannot tell which change helped.

## The Own-PHP-Version Trick (and What It Costs)

On Nginx servers, each PHP version has its own OPcache. If one busy site crowds out the others, move it to a PHP version no other site on the server uses. It then gets a cache of its own, and the other sites stop competing with it.

| | Shared PHP version | Own PHP version for one site |
|---|---|---|
| OPcache | One cache for all sites | Separate cache for that site |
| RAM | One cache reserved | One more cache reserved, plus one more PHP service |
| Settings | One set for all | A separate set to tune |
| Updates | One version to patch | One more version to keep updated |
| Best for | Many small and medium sites | One large store or a site with heavy plugins |

The catch worth knowing: switching PHP versions can break an old plugin. Test the switch on a [**staging site**](/docs/how-to-create-a-staging-environment-in-xcloud/) first.

## Doing It on xCloud

Here is what xCloud does for OPcache today, checked against its code and the [**OPcache guide**](/docs/control-opcache-with-xcloud/).

**What xCloud does:**

- **OPcache is on for every PHP version xCloud installs.** You switch it per version under **Server → Management → Manage PHP**, in the **'OPCache'** column of the **'PHP Configuration'** tab.
- **Larger defaults than PHP.** xCloud starts each PHP version with 512 MB of memory, a 32 MB interned strings buffer, 100,000 max files and a 60-second revalidate frequency (PHP's own defaults are 128 MB, 8 MB, 10,000 and 2 seconds).
- **One screen per PHP version.** Open any site, go to **Site Settings → PHP Configurations → OPcache settings → Edit**, change the four values and click **'Save Settings'**. xCloud writes them for that PHP version and, on Nginx servers, restarts PHP for it. On OpenLiteSpeed servers, saving restarts the web server, so every site on the server can pause for a moment.
- **Auto-tune.** The **'✨ Auto-tune'** button reads the server's RAM and suggests values: 128 MB up to 2 GB of RAM, 256 MB up to 8 GB, 512 MB above that, always 100,000 files, and 8, 16 or 32 MB for the interned strings buffer on the same RAM tiers. Nothing changes until you save.
- **A different PHP version per site.** Change it in the site's settings, as shown in [**how to change a site's PHP version**](/docs/how-to-upgrade-php-version-with-xcloud-hosting/).

![Auto-tune in xCloud fills in OPcache values based on the server's RAM](/_landing/docs/control-opcache-with-xcloud-image-4.png)

**What xCloud does not do:**

- **It does not show the OPcache hit rate in the dashboard.** Use the PHP file above to check it.
- **Auto-tune looks at RAM, not at how many sites you run.** On a server with many sites on one PHP version, its suggestion can be smaller than the 512 MB default. Check the hit rate before you save a smaller value.
- **It does not give each site its own cache on a shared PHP version.** Use a separate PHP version for that.

For the rest of PHP's settings (memory limit, upload size, execution time), see [**how to configure PHP settings**](/docs/how-to-configure-php-settings/). If the server is also short on PHP processes, [**adjust PHP workers**](/docs/how-to-adjust-php-workers-in-xcloud/) next.

👉 Running many WordPress sites on one server? [**xCloud WordPress hosting**](/hosting-for-wordpress/) sets OPcache up this way on every server, and [**PHP hosting**](/php-hosting/) does the same for plain PHP apps.

## Honest Limits

OPcache only removes the cost of compiling PHP. It does not make slow database queries faster, and it does not fix a plugin that calls an external API on every admin page. If the hit rate is already close to 100%, look at [**server resource usage**](/docs/how-to-monitor-server-resource-usage-with-xcloud/) and your plugins instead.

How much faster wp-admin gets after a fix depends on the site, so this guide gives no speed numbers.

**To undo a change,** open the same OPcache popup, put the previous values back and save. The xCloud defaults are 512 MB, 32 MB, 100,000 files and 60 seconds.

Two side effects to plan for:

- **More memory for OPcache is less memory for everything else.** On a 2 GB server, 512 MB is a large share of the RAM.
- **Revalidate frequency delays code changes.** At 60 seconds, a file you edit can take up to a minute to show. Set it to 0 while you develop, then back to 60.

## Fix Your Shared OPcache Before You Blame wp-admin

If one Nginx server runs many WordPress sites, the OPcache settings are shared by every site on the same PHP version. Read the hit rate, free memory, cached keys and restarts first. Then raise the one limit that is full, and give a separate PHP version only to the site that crowds everyone else out.

This week: drop the check file on one site per PHP version, read the four numbers after a normal day, and delete the file. For more speed work, see our [**tips to speed up WordPress websites**](/tips-to-speed-up-wordpress-websites/), the [**Redis object caching guide**](/advanced-redis-object-caching-for-wordpress/) and our [**PHP hosting setup checklist**](/php-hosting-setup-checklist/).

If you have found this blog helpful, feel free to [**subscribe to our blogs**](https://xcloud.host/blog/) for valuable tutorials, guides, knowledge, and tips on web hosting and server management. You can also join our [**Facebook community**](https://www.facebook.com/groups/xcloud.community) to share insights and engage in discussions.

## Frequently Asked Questions

### Does each WordPress site get its own OPcache?

Not on a typical server. PHP keeps one OPcache per running PHP service, and on Nginx servers that means one cache per PHP version. Ten sites on PHP 8.3 share one block of OPcache memory and one file limit.

### How much OPcache memory do I need for 10 WordPress sites?

There is no fixed number, because it depends on how many plugins and themes each site loads. Start from a generous value such as 512 MB, let the sites run for a day, then check free memory and the restart counters. Raise it if free memory is near zero, lower it if a large share stays unused.

### Why is my wp-admin slow when the front end is fast?

Your page cache serves visitors, but logged-in admin pages always run PHP. If OPcache is too small for all the sites on that PHP version, admin code keeps getting compiled again. Check the hit rate and the restart counters before you blame the database or a plugin.

### Can I check the OPcache hit rate from the command line?

Not reliably. PHP on the command line has its own OPcache, which is switched off by default (opcache.enable_cli is 0), so it does not show your sites' cache. Check it from a PHP file the web server runs, then delete the file.

### Will changing OPcache settings on xCloud restart my sites?

On Nginx servers, saving the OPcache settings restarts PHP for that PHP version, so every site on that version can pause for a moment. On OpenLiteSpeed servers, saving restarts the web server, so every site on the server can pause for a moment. Save at a quiet time. The values stay the same until you click Save Settings.

### Should I give every site its own PHP version?

No. Give a separate PHP version only to the one or two sites that crowd the cache, such as a large WooCommerce store. Each extra version uses its own memory and is one more PHP version to keep updated.
