PHP-FPM for WordPress – Pool Configuration, OPcache, and Security
Published: April 14, 2026 · Author: Marcin Szewczyk-Wilgan
PHP-FPM (FastCGI Process Manager) is the PHP execution environment behind every well-configured WordPress server. Understanding how it works – and how to configure it correctly – makes the difference between a server that handles traffic spikes gracefully and one that crashes under load. This article covers the complete PHP-FPM setup for WordPress: pool configuration, process management modes, Unix socket vs TCP, OPcache and JIT, Redis object cache, and security hardening with open_basedir and disable_functions.
How PHP-FPM Works
PHP-FPM manages a pool of PHP worker processes. When Nginx or Apache receives a PHP request, it hands it off to PHP-FPM via the FastCGI protocol. PHP-FPM assigns the request to an available worker, which executes the PHP code and returns the result. The web server then sends the response to the client.
fastcgi_pass directive in Nginx points to either a Unix socket (unix:/var/run/php-fpm/wordpress.sock) or a TCP address (127.0.0.1:9000). Unix sockets are faster for same-server setups; TCP is required when PHP-FPM runs on a separate host.Calculating pm.max_children
The most critical PHP-FPM configuration parameter is pm.max_children – the maximum number of PHP worker processes. Set it too low and requests queue or timeout under load; set it too high and workers compete for RAM, triggering swapping and catastrophic performance degradation.
(Available RAM − OS overhead − MySQL RAM − web server RAM) ÷ average PHP worker size × 0.85The 0.85 factor provides a safety margin so you never push the server to exactly its memory limit under burst load.
ps aux --sort=-%mem | grep php-fpm | awk '{print $6}' gives RSS in KB. Divide by 1024 for MB. Average 5–10 readings after normal use.pm.max_children = 27.pm.max_requests = 500 to recycle workers after 500 requests. This prevents memory leaks from accumulating indefinitely. A worker is gracefully replaced by a fresh one after hitting the limit. Values between 200 and 1000 are reasonable; lower values catch leaks faster at the cost of slightly more spawn overhead.Process Management Modes
PHP-FPM offers three process management modes. The right choice depends on your traffic pattern and available memory.
Variable traffic – the default
Starts with pm.start_servers workers (e.g., 5), maintains at least pm.min_spare_servers idle workers, and spawns more up to pm.max_children when load increases. Idle workers above pm.max_spare_servers are gracefully terminated. Ideal for sites with variable traffic patterns.
Consistent high traffic
Keeps exactly pm.max_children workers running at all times, regardless of load. Eliminates spawn latency under traffic spikes. Requires more RAM when idle but is the best choice for high-traffic sites where spawn overhead would be noticeable. Set pm.max_children to a value your server can sustain continuously.
Low-traffic or idle sites
Starts zero workers and spawns them only when a request arrives. Workers are killed after pm.process_idle_timeout (default 10 seconds) of inactivity. Saves memory on servers hosting many low-traffic sites. The spawn latency on first request is noticeable, making this inappropriate for sites with consistent traffic.
Performance diagnostics
Enable slowlog = /var/log/php-fpm/wordpress-slow.log and request_slowlog_timeout = 10s to capture stack traces of requests that take longer than 10 seconds. This is invaluable for diagnosing performance issues caused by specific plugins, database queries, or external API calls.
Unix Socket vs TCP
When Nginx and PHP-FPM run on the same server, Unix sockets are always preferable to TCP connections on the loopback interface.
fastcgi_pass unix:/var/run/php/php8.3-fpm-wordpress.sock;The socket file path must match the
listen directive in your PHP-FPM pool configuration: listen = /var/run/php/php8.3-fpm-wordpress.sock.listen.owner = www-data, listen.group = www-data, and listen.mode = 0660 in the pool configuration. Nginx runs as www-data and must have read/write access to the socket file. Incorrect permissions cause connect() to unix:/...sock failed (13: Permission denied) errors.127.0.0.1:9000 or a specific port) when PHP-FPM runs on a separate server from the web server, or when load balancing across multiple PHP-FPM hosts. TCP is the only option when the connection crosses a network boundary.OPcache and JIT
OPcache is the single most impactful PHP performance optimization for WordPress. JIT (introduced in PHP 8.0) provides further gains for specific workloads.
opcache.memory_consumption = 256 (MB of shared memory for cached bytecode), opcache.max_accelerated_files = 20000 (WordPress + plugins can easily have 10,000+ PHP files), opcache.validate_timestamps = 0 (disable file change checks in production for best performance – reload PHP-FPM after deployments to clear cache), opcache.revalidate_freq = 60 (seconds between file checks if validate_timestamps is 1).opcache.jit = tracing and opcache.jit_buffer_size = 64M.Security Hardening
PHP-FPM configuration is also where security isolation is enforced. These settings limit what PHP can do if a vulnerability is exploited.
Restricting file system access
Set php_admin_value[open_basedir] = /var/www/site:/tmp:/usr/share/php to prevent PHP from reading files outside the WordPress installation. If a vulnerability is exploited and an attacker runs PHP code, they cannot read /etc/passwd, access other sites' files, or read credentials from outside the allowed paths.
Blocking dangerous functions
Disable PHP functions that WordPress does not need but attackers do: php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen,pcntl_exec. These functions allow PHP to execute system commands. Legitimate WordPress plugins do not need them; most malware does.
Separate pools per site
Run each WordPress site under a dedicated Unix user with its own PHP-FPM pool. Set user = www-wp-site1 and group = www-wp-site1. This ensures that code running under site1's PHP process cannot read or write files owned by site2. Critical for shared hosting and agency multi-site servers.
Preventing runaway processes
Set php_admin_value[memory_limit] = 256M to cap memory per request, and configure request_terminate_timeout = 60s to kill requests that run longer than one minute. These limits prevent a single runaway plugin or crashed script from consuming all server resources.
Summary
Correctly configured PHP-FPM is one of the highest-leverage infrastructure improvements for a WordPress server. The combination of properly calculated pm.max_children, Unix socket communication, OPcache with adequate shared memory, and Redis object cache typically reduces server response times by 60–80% compared to a default PHP-FPM installation. Security hardening with open_basedir, disable_functions, and per-site process isolation significantly reduces the blast radius of any plugin vulnerability that gets exploited. These are not optional extras for production servers – they are the baseline configuration.
See also: Nginx for WordPress · Apache for WordPress · WordPress Caching


