PHP-FPM Tuning

An Introduction to PHP-FPM Tuning

BONUS: We had a conversation with an industry expert in the PHP community about this topic. Listen to our podcast here.

PHP-FPM (Fast Process Manager) offers several advantages over mod_php. It is highly configurable and widely preferred by the PHP community. However, if you’re using the default settings from your package manager, you might not be optimizing its performance.

In this article, we will provide an overview of PHP-FPM’s performance optimization. We will discuss the three process manager types it offers and guide you on choosing the most suitable one for your specific needs.

PHP-FPM supports three process management types:

  • Static
  • Dynamic
  • Ondemand

Let’s take a closer look at each type.


Static mode ensures a fixed number of child processes are always available to handle user requests. This approach, defined by the pm.max_children setting, eliminates the need for requests to wait for new processes to start, making it the fastest option.

To configure the static mode with, for example, 10 child processes in the /etc/php/7.2/fpm/pool.d/www.conf file (assuming you’re using the default PHP-FPM configuration for Debian/Ubuntu), use the following settings:

pm = static
pm.max_children = 10

After restarting PHP-FPM, you can verify the configuration changes by running the command pstree -c -H <PHP-FPM process id> -S <PHP-FPM process id>. This will show that ten processes are available.



In dynamic mode, PHP-FPM manages the number of available child processes dynamically and ensures that at least one child process is always available.

See also  PHP Performance Monitoring

This mode requires configuring the following options:

  • pm.max_children: The maximum number of child processes allowed.
  • pm.start_servers: The number of child processes to start when PHP-FPM starts.
  • pm.min_spare_servers: The minimum number of idle child processes PHP-FPM will create. More processes are created if fewer than this number are available.
  • pm.max_spare_servers: The maximum number of idle child processes PHP-FPM will create. If there are more processes than this value, some will be killed off.
  • pm.process_idle_timeout: The duration of idle time (in seconds) after which a child process will be terminated.

To calculate the optimal values for each setting, you can use the following formula provided by Sebastian Buckpesch:

Setting Value
max_children (Total RAM – Memory used for Linux, DB, etc.) / process size
start_servers Number of CPU cores x 4
min_spare_servers Number of CPU cores x 2
max_spare_servers Same as start_servers

You should also set a value for pm.process_idle_timeout, which represents the number of seconds after which an idle process will be terminated.

For example, let’s assume that your server has two CPUs, each with four cores, and 8GB of RAM. After subtracting the memory used by Linux and related processes (approximately 2GB), you have around 6192MB available.

To determine the memory usage per process, you can run the Python script After executing sudo python | grep php-fpm, you’ll see the memory usage:

28.4 MiB + 33.8 MiB = 62.2 MiB php-fpm7.2 (11)

Based on this information, you can use the formula provided earlier to calculate the values:

# Round the result up. (8192 - 2000) / 62.2

Setting | Value
--- | ---
max_children | 100
start_servers | 32
min_spare_servers | 16
max_spare_servers | 32

Assuming you’re satisfied with these settings, update your configuration as follows:

pm = dynamic
pm.max_children = 100
pm.start_servers = 32
pm.min_spare_servers = 16
pm.max_spare_servers = 32
pm.max_requests = 200

If you want to monitor your application’s memory usage regularly, you can utilize various PHP memory monitoring tools such as php-memprof and Tideways.

See also  Is Outsourcing PHP Development the Right Choice?


In ondemand mode, PHP-FPM forks processes upon receiving requests. To configure PHP-FPM in ondemand mode, set pm to ondemand and provide values for pm.max_children, pm.process_idle_timeout, and pm.max_requests.

The max_requests setting defines the number of requests each child process should handle before respawning. This setting can help mitigate memory leaks.

Assuming you want to use the same settings as dynamic, configure PHP-FPM as follows:

pm = ondemand
pm.max_children = 100
pm.process_idle_timeout = 10s
pm.max_requests = 200

Which Configuration Is Right For You?

Honestly, the answer is: “it depends.” The optimal configuration depends on the type of applications you are running. However, here are some recommendations:

Low Traffic Site

If you have a low-traffic site that hosts a backend control panel, like cPanel, using ondemand is recommended. This mode saves memory as child processes are only spawned when necessary and terminated when no longer needed. Since it’s a backend, users can tolerate a slight delay while a thread spawns to handle their request.

High Traffic Site

For high traffic websites, the static mode is advised. Adjust the settings based on your specific needs and available hardware resources over time. Although having a large number of child processes might seem excessive, it ensures quick response times for high-traffic scenarios.

Using ondemand may result in excessive memory consumption due to frequent process spawning and termination, leading to a performance hit. The dynamic mode can be an alternative, but it might end up resembling static if not properly configured.

Using Multiple Pools for Frontend/Backend

Now, let’s discuss serving the frontend and backend of your website through different PHP-FPM pools. For example, consider an e-commerce site powered by Magento. You can divide the application into two parts:

  • Frontend: Where customers browse and make purchases
  • Backend: Where admin staff manages the shop, including product management and reviews
See also  PHP Mental Health Program: Your Path to Recovery

To achieve this, create two separate pools, one for the frontend and another for the backend, with appropriate configurations.

In the /etc/php/7.2/fpm/pool.d/www.conf file, add the following configuration:

; frontend
listen = /var/run/php-fpm-frontend.sock
user = www-data
group = www-data
listen.owner = www-data = www-data
pm = static
pm.max_children = 5

; backend
listen = /var/run/php-fpm-backend.sock
user = www-data
group = www-data
listen.owner = www-data = www-data
pm = ondemand
pm.max_children = 5
pm.process_idle_timeout = 10s

These pool configurations specify different sockets and process manager settings for the frontend and backend pools. Both pools share the same user and group.

In your NGINX vhost file, use the following configuration:

server {
    listen 80;
    server_name test-site.localdomain;
    root /var/www/test-site/public;
    access_log /var/log/nginx/test-site.access.log;
    error_log /var/log/nginx/test-site.error.log error;
    index index.php;

    set $fpm_socket "unix:/var/run/php-fpm-frontend.sock";

    if ($uri ~* "^/api/") {
        set $fpm_socket "unix:/var/run/php-fpm-backend.sock";

    location / {
        try_files $uri $uri/ /index.php;

        location ~ .php$ {
            fastcgi_split_path_info ^(.+.php)(/.+)$;
            fastcgi_pass $fpm_socket;
            fastcgi_index index.php;
            include fastcgi.conf;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

This configuration creates a virtual host that directs requests to either the frontend or backend pool based on the requested location. Requests to “/api” are forwarded to the backend pool, while all other requests are routed to the frontend pool.

In Conclusion

This article provided a rapid introduction to tuning PHP-FPM for improved performance. We discussed the three process manager configurations available, their related settings, and suggested appropriate use cases for each configuration. Additionally, we explored the concept of worker pools.

For more information about PHP-FPM tuning and other tech-related topics, visit ProgramMatek.