What Is PHP OPcache
PHP OPcache speeds up PHP script execution by keeping compiled byte-code in shared memory. On repeat requests PHP skips the parsing and compilation stages, which yields a speed gain of 2 to 10 times. OPcache is enabled in PHP 5.5+ and ships with PHP itself — no separate installation is required.
Checking OPcache Status
php -r "echo opcache_get_status() ? 'Enabled' : 'Disabled';"Or create the file /var/www/html/opcache-info.php:
<?php
$status = opcache_get_status();
echo "Memory used: " . round($status['memory_usage']['used_memory']/1024/1024) . " MB\n";
echo "Hit rate: " . round($status['opcache_statistics']['opcache_hit_rate'], 2) . "%\n";Enabling and Configuring OPcache
Open the file /etc/php/8.2/fpm/php.ini or create /etc/php/8.2/mods-available/opcache.ini:
opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
opcache.validate_timestamps=1
opcache.save_comments=1
opcache.fast_shutdown=1Key Parameters Explained
| Parameter | Value | Description |
|---|---|---|
memory_consumption | 128–512 MB | RAM for the byte-code cache |
max_accelerated_files | 4000–100000 | Maximum number of cached files |
revalidate_freq | 0 (prod) / 2 (dev) | How often file changes are checked (sec) |
validate_timestamps | 0 (prod) / 1 (dev) | Whether to check file modification time |
validate_timestamps=0 and revalidate_freq=0 — that is maximum speed. After deploying code, flush the cache with php -r "opcache_reset();" or by reloading PHP-FPM.Optimal Settings for WordPress / Laravel
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.revalidate_freq=0
opcache.validate_timestamps=0
opcache.interned_strings_buffer=16
opcache.jit=1255
opcache.jit_buffer_size=128MJIT Compilation in PHP 8.x
PHP 8.0+ supports JIT (Just-In-Time) compilation on top of OPcache. For CPU-intensive workloads (image processing, cryptography, scientific computing) JIT delivers an extra speed-up:
opcache.jit=1255
opcache.jit_buffer_size=128MResetting the OPcache
# Via PHP CLI
php -r "opcache_reset();"
# Reload PHP-FPM
sudo systemctl reload php8.2-fpm
# Via wp-cli (for WordPress)
wp cache flushReal OPcache Errors
Not enough shared memory
PHP Warning: PHP Startup: Unable to allocate shared memory segment of 268435456 bytes in Unknown on line 0Most often seen inside Docker containers: by default /dev/shm is capped at 64 MB, while opcache.memory_consumption asks for 256 MB. The fix is either to increase the container's --shm-size, or to lower the cache's memory allocation to what is actually available.
The cache silently fills up
The trickiest OPcache situation comes with no error text at all. When the number of project files exceeds opcache.max_accelerated_files, new files simply stop being cached: the site does not crash, it just quietly gets slower. The only way to spot this is by checking the status:
php -r "var_dump(opcache_get_status()['cache_full']);"
// bool(true) — the cache is full, new scripts get recompiled on every requestWhen OPcache Is Nearly Useless
- Short-lived CLI scripts (one-off handlers, single-line cron jobs) — every run is a fresh process with no shared memory with the previous one, so there is nothing to cache. That is why
opcache.enable_cli=0is the default. - Long-running queue workers are the exception to that rule: if a process lives for hours and reuses the same code, turning on
opcache.enable_cli=1for it is worthwhile. - Active development with
validate_timestamps=0— file changes stop being picked up entirely, not just with a delay, which looks like "my edit did not apply" and causes confusion until someone remembers this setting.
Verifying the Result
| Status field | Healthy value |
|---|---|
| opcache_hit_rate | Above 95% |
| cache_full | false |
| num_cached_scripts | Close to the total number of PHP files in the project |
php -r '
$s = opcache_get_status();
echo "hit_rate: " . round($s["opcache_statistics"]["opcache_hit_rate"], 1) . "%
";
echo "cache_full: " . var_export($s["cache_full"], true) . "
";
echo "cached: " . $s["opcache_statistics"]["num_cached_scripts"] . "
";
'If cache_full is true, raise opcache.max_accelerated_files with headroom: count the actual number of PHP files in the project with find . -name "*.php" | wc -l and use a value at least twice that. For fine-tuning JIT on top of OPcache, see the dedicated article.
Keep at least a 1.5–2x margin: the number of project files growing after a framework update or a new library pulled in through Composer is routine, and without headroom the cache will fill up again within a couple of releases.