EN
Webmail

PHP-FPM Tuning for WordPress: Workers, Memory and Slow Requests

PHP-FPM Tuning for WordPress: Workers, Memory and Slow Requests

PHP-FPM is the process manager that runs PHP code for most modern WordPress servers, and its settings decide how many visitors your site can serve at the same moment. When the configuration is left at defaults, a quiet site works fine, a busy one starts to show slow pages and 502 or 504 errors, and a badly sized one can run the server out of memory. Tuning PHP-FPM is not about secret tricks. It is about understanding a few numbers, measuring how much memory each PHP process really uses, and setting limits that fit the machine you have.

This guide explains what PHP-FPM does, the main pool settings and what they mean, how to calculate a sensible number of workers for a WordPress site, how to find slow requests, how to read the symptoms of a poorly tuned pool and how to change settings safely on a production server. It assumes you manage a Linux server or work with someone who does. If you only use shared hosting, you cannot change most of these settings, but knowing them helps you ask the right questions.

What PHP-FPM Does

A web server such as Nginx or Apache does not run PHP itself in the modern setup. It passes each request for a PHP page to PHP-FPM, which keeps a group of worker processes ready. Each worker handles one request at a time: it runs the WordPress code, talks to the database, builds the page and returns the result. When all workers are busy, new requests wait in a queue. If the queue grows or the wait is too long, visitors see a slow page or an error from the web server.

The workers belong to a pool, and a server can run several pools, for instance one per website, each with its own user, limits and settings. This separation improves security and lets you give a busy shop more capacity than a small brochure site. The official PHP-FPM configuration reference lists every directive, though the handful below cover most real-life needs.

The Settings That Matter

SettingWhat it doesTypical consideration
pmChooses the process manager mode: static, dynamic or ondemandDynamic is the common default, static suits stable busy sites, ondemand saves memory on many small sites
pm.max_childrenMaximum number of workers in the poolThe most important limit. Too high exhausts memory, too low causes queues
pm.start_serversWorkers created at start in dynamic modeSet between the minimum and maximum spare values
pm.min_spare_servers and pm.max_spare_serversRange of idle workers kept readyKeep enough for sudden bursts without wasting memory
pm.max_requestsNumber of requests before a worker is recycledA modest value limits slow memory leaks from plugins
pm.process_idle_timeoutIdle time before an ondemand worker is stoppedOnly for ondemand mode
request_terminate_timeoutTime after which a stuck request is killedProtects against runaway scripts
request_slowlog_timeout and slowlogLog a stack trace for requests slower than the limitExcellent for finding slow plugins
php_admin_value[memory_limit]Maximum memory a single PHP request may useNot the same as average use, and a worker can exceed typical figures on heavy admin tasks

Understand the three modes first. In static mode, the pool always keeps exactly the maximum number of workers. This is simple and fast under steady load, but wastes memory when traffic is low. In dynamic mode, the pool creates and removes workers between the minimum and maximum spare numbers, which adapts to changing traffic. In ondemand mode, workers start only when requests arrive and stop after an idle period. That saves memory on servers with many rarely visited sites, at the cost of a small delay when the first request has to start a worker.

Calculating pm.max_children for WordPress

The key question is how many workers the server can afford. The answer comes from memory, not from guessing. Follow these steps on the real machine.

  1. Find the memory available for PHP. Start with total memory and subtract what the operating system, the database, the web server and caches such as Redis use. On a small server that also runs MySQL, PHP may only get a half of the memory. Our guide to server capacity planning shows how to account for the other parts.
  2. Measure the average worker size. Under normal traffic, list the PHP-FPM processes with their resident memory and take the average. A plain WordPress site may use around thirty to sixty megabytes per worker, while a WooCommerce shop with many plugins can use much more. Use the actual figure, not a number from an article, including this one.
  3. Divide. Available memory divided by average worker size gives a safe upper bound. Leave a margin of at least ten to twenty percent for bursts and for the operating system file cache.
  4. Check processor limits. More workers than processor cores do not make a CPU-bound site faster. If requests spend time waiting for the database or external services, extra workers help, but only until the database becomes the bottleneck.
  5. Set and observe. Apply the number, then watch memory, load and the pool status for several days.

As an example, a server has eight gigabytes of memory. After the system, database and cache are accounted for, about four gigabytes remain for PHP. The measured average worker is eighty megabytes. Four thousand divided by eighty gives fifty, and subtracting a margin leaves roughly forty workers as a ceiling. If the server has four cores and the site mostly runs short, cached requests, a lower number such as twenty-five may be enough and leaves more room for the database.

Reading the Symptoms

The web server error log and the PHP-FPM log tell you whether the pool is too small, too large or fine.

  • “server reached pm.max_children setting” in the log means all workers were busy and requests waited. Look at the causes before raising the limit: a slow plugin, a slow database query or an external API call can keep workers occupied. If the server has spare memory and the requests are healthy, raising the limit is the fix.
  • Frequent 502 or 504 errors. A 502 can mean a worker crashed or was killed, and a 504 means a request took longer than the proxy timeout. Check the slow log and the system log for out-of-memory kills.
  • Memory climbing until the kernel kills processes. The pool is too large for the machine, or a plugin leaks memory. Lower pm.max_children and use pm.max_requests to recycle workers. Our article on Linux out-of-memory errors explains how to read these events.
  • High load but idle workers. The bottleneck is elsewhere, perhaps the database or the disk. More workers will not help.
  • Fast pages at night, slow in the daytime. Check the queue length and the number of active processes during the peak with the status page.

Finding Slow Requests

Tuning numbers fixes capacity, but slow code still needs diagnosis. PHP-FPM has two built-in aids.

The Status Page

Enable pm.status_path for the pool and restrict access to the local machine or to trusted addresses. The page shows active and idle processes, the listen queue, the number of requests and how often the limit was reached. Watch the “max children reached” counter and the queue length. A counter that rises at peak hours is the clearest evidence for adjusting the limit.

The Slow Log

Set slowlog to a file path and request_slowlog_timeout to a value such as five seconds. When a request exceeds it, PHP-FPM writes the call stack, which shows which file and function were running. In WordPress, the stack often points to a plugin, a remote HTTP call or a database query. Use the information to remove or replace the offender, to cache the result or to fix the query, as described in our guide to WordPress database optimisation.

Also set request_terminate_timeout to a sensible value, so that a stuck script cannot hold a worker forever. Check that it is compatible with the maximum execution time in PHP settings and with the timeouts of the web server, since the shortest limit wins.

Memory, Opcache and Caching

Worker size depends on more than WordPress. The opcode cache stores compiled PHP code in shared memory, which speeds up every request and reduces CPU use, and it is usually enabled by default in current PHP versions. Give it enough memory for all the files in your sites, and check its hit ratio. A page cache that serves static copies to anonymous visitors reduces the number of requests that reach PHP at all, which is often more effective than adding workers. An object cache keeps database results in memory, as described in our article on object caching for WordPress. Together, these layers mean fewer and faster PHP requests, and a smaller pool is enough.

Keep PHP itself current, and read the FastCGI Process Manager chapter of the PHP manual for the details of each directive. Newer versions are faster and use less memory, and old ones lose security support. Plan upgrades carefully with staging tests, following the steps in our guide to PHP version upgrades.

Applying Changes Safely

  1. Back up the configuration. Copy the pool file before editing, and note the date and reason.
  2. Change one thing at a time. Adjust the maximum number of workers or the mode, not several settings together, so that you can tell what helped.
  3. Test the syntax. PHP-FPM has a test option that checks the configuration without restarting. Use it before every reload.
  4. Reload instead of restart. A graceful reload lets running requests finish. Do it outside peak hours where possible.
  5. Watch after the change. Follow the error log, the status page and memory for at least a day, and a full week if traffic varies by weekday.
  6. Document the values and the reasoning. A short note such as “average worker 70 MB, 4 GB for PHP, limit 40” lets the next administrator understand the choice.

On servers managed with a control panel, edit the pool through the panel or its configuration templates, because manual changes can be overwritten at the next update. If you would rather have a specialist review the setup, our server administration team can measure, tune and monitor it for you.

A Worked Example

A small online shop runs on a virtual server with six gigabytes of memory, the MySQL database and PHP-FPM in the default dynamic mode with a maximum of five children. During a weekend promotion the site slows down, and the log shows repeated messages that the pool reached its limit. The administrator checks the processes under load and measures an average of about ninety megabytes per worker. After the database, the web server and Redis, roughly three gigabytes remain for PHP, which suggests a ceiling of about thirty workers, and a safe setting of twenty-four.

She changes the pool to twenty-four children, with start and spare values matching, adds a recycle limit of five hundred requests and enables the slow log at five seconds. The next promotion passes without queues. The slow log, however, shows repeated stack traces from a shipping rate plugin that calls an external service on every cart update. The shop replaces the plugin with a cached alternative, which reduces the PHP time per request. Within a month, the average worker count in use falls, and the administrator lowers the maximum a little to leave more memory for the database. The server runs better with a smaller pool than before, because the code now does less work.

Common Mistakes

  • Setting pm.max_children to a large number “to be safe”, then running out of memory under load.
  • Copying values from a blog post without measuring the real worker size.
  • Raising the limit to hide a slow plugin or database query.
  • Leaving the slow log disabled, so there is no evidence for the real cause.
  • Forgetting that the database and caches need memory as well.
  • Using static mode on a server with several quiet sites, wasting memory.
  • Exposing the status page to the public internet.

Frequently Asked Questions

What is the best PHP-FPM mode for WordPress?

Dynamic is a good general choice. Use static on a dedicated server with steady heavy traffic, and ondemand on a server with many small, rarely visited sites where saving memory matters more than the first-request delay.

How many PHP-FPM workers do I need?

Divide the memory available for PHP by the average memory of one worker, leave a margin, and check the processor and database limits. Then adjust based on the status page and logs during peak traffic.

Why do I get 502 or 504 errors on my WordPress site?

Common reasons are all workers being busy, a worker killed for memory, a script that runs longer than the timeout or a crash in a plugin. Check the PHP-FPM log, the web server log and the system log to find which one applies.

Does increasing workers make the site faster?

Only if requests were waiting for a free worker and the server has spare memory and processor capacity. If the site is slow because of code or the database, more workers can make it worse.

What does pm.max_requests do?

It restarts a worker after a set number of requests, which limits the effect of slow memory leaks in plugins or extensions. A value in the hundreds is common, and zero means workers are never recycled.

Can I tune PHP-FPM on shared hosting?

Usually not, because the host controls the pool. You can still reduce load with caching, fewer plugins and a current PHP version, and ask the host about limits on processes and memory.

The Bottom Line

PHP-FPM tuning is mostly arithmetic and observation. Measure the real memory of a worker, work out how many fit beside the database and caches, set pm.max_children below that ceiling, and use the status page and slow log to see whether requests queue or run too long. Fix slow plugins and queries rather than only adding workers, apply changes one at a time with a tested reload and keep notes of the reasoning. A well-sized pool turns traffic spikes into a short queue instead of an outage.