WordPress performance problems often get blamed on plugins when the server is simply running the wrong PHP-FPM settings. The goal is not to copy a magic config. The goal is to match worker counts, memory, caching, and logs to the server you actually have.
Start with memory, not CPU
PHP-FPM creates workers. Each worker consumes memory. If you allow too many workers, the server swaps and every request gets slower.
Check average PHP process size:
ps --no-headers -o rss -C php-fpm8.3 | awk '{sum+=$1; n++} END {print int(sum/n/1024) " MB"}'
Then estimate:
available RAM for PHP / average worker size = safe max_children
Leave memory for MySQL, Redis, Nginx, the OS, backups, and monitoring. On a 4 GB VPS, that usually means PHP gets 1.5-2 GB, not the full machine.
PHP-FPM pool settings that matter
For a typical 4 GB WordPress VPS:
pm = dynamic
pm.max_children = 18
pm.start_servers = 4
pm.min_spare_servers = 4
pm.max_spare_servers = 8
pm.max_requests = 500
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/wordpress-slow.log
Increase max_children only after watching memory during real traffic. If listen queue grows but RAM is fine, you can raise it. If swap is active, lower it.
Enable OPcache properly
OPcache avoids parsing PHP files on every request:
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=30000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
For WordPress, validate_timestamps=1 is the practical default. Setting it to 0 is faster but requires a deploy process that resets OPcache after every plugin or theme update.
Nginx buffers and timeouts
These defaults work for most WordPress sites:
client_max_body_size 64m;
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 120s;
fastcgi_read_timeout 120s;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
If uploads fail, raise client_max_body_size. If admin actions time out, look at PHP slow logs before increasing timeouts endlessly.
Use FastCGI cache carefully
Full-page cache at Nginx is excellent for brochure sites and risky for logged-in or ecommerce flows. Bypass cache for:
- Logged-in users
- WooCommerce cart, checkout, and account pages
- Requests with comment, cart, or session cookies
- POST requests
If you cannot explain the bypass rules, use a WordPress caching plugin or Cloudflare APO instead.
Watch these metrics after changes
Run:
systemctl status php8.3-fpm
journalctl -u php8.3-fpm --since "1 hour ago"
tail -f /var/log/php-fpm/wordpress-slow.log
free -m
vmstat 1
Good tuning produces fewer 502s, less swapping, and clearer slow logs. Bad tuning hides the problem until traffic spikes.
When to stop tuning
Stop when:
- The server is not swapping
- PHP-FPM has spare workers during normal traffic
- Slow logs identify application-level bottlenecks
- Cached pages respond quickly
- Uncached admin requests are acceptable
After that, performance work belongs in WordPress: database queries, plugin audits, object cache, image optimisation, and fewer expensive third-party calls.