June 18 2022

Introduction to PHP-FPM tuning

How to fine-tune PHP FPM tuning? Let's see a short guide.

PHP FPM Tuning and Configuration

PHP-FPM (or Fast Process Manager) offers several advantages over mod_php, with two of the most notable being more flexible to configure and currently the preferred way of running PHP by many in the community. However, if you're using your package manager's default configuration settings, you probably won't get the most of them.

In this post, I'll give a brief overview of how improve PHP-FPM performance by discussing the three types of PHP-FPM process managers and which one is best to use in which circumstance.

PHP-FPM can use one of the three types of process management :

  • static (static)
  • dynamic (dynamic)
  • ondemand (on request)

Let's take a look at what each is in a bit of detail by going to identify the pros and cons of the three different modes that can still coexist quietly on the same server.

For example, we could have three websites on the same server, one of which runs in static mode, one ondemand and one dynamic without any restrictions and with a total separation of privileges.

PHP in Static mode

Static ensures that a fixed number of child processes are always available to handle user requests. This is set with pm.max_children . In this mode, requests don't have to wait for new processes to start, which makes it the fastest approach.

Assuming you want to use static configuration with 10 child processes always available, you should configure it /etc/php/7.2/fpm/pool.d/www.conf(assuming you are using Debian / Ubunut's default PHP-FPM configuration file) as follows:

pm = static pm.max_children = 10 

To see if the configuration change was effective, after restarting PHP-FPM, run pstree -c -H <PHP-FPM process id> -S <PHP-FPM process id>. This will show that there are ten processes available, as in the example below.

php-fpm7.2-+-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            `-php-fpm7.2 

PHP in Dynamic mode

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

This configuration uses five configuration options; these are:

  • pm.max_children: the maximum number of child processes that can be spawned.
  • pm.start_servers: the number of child processes to start when PHP-FPM starts.
  • pm.min_spare_servers: the minimum number of inactive child processes that PHP-FPM will create. More are created if fewer than this number are available.
  • pm.max_spare_servers: The maximum number of inactive child processes that PHP-FPM will create. If there are multiple child processes of this value, some will be deleted.
  • pm.process_idle_timeout: the idle time, in seconds, after which a child process will be terminated.

Now comes the fun part; how do you calculate the values ​​for each setting? Sebastian Buckpesch , proposes the following formula:

Setting Value
max_children (Total RAM - Memory used for Linux, DB, etc.) / process size
start_server Number of CPU cores x 4
min_spare_servers Number of CPU cores x 2
max_spare_servers Equal tostart_servers

We also need to set up pm.process_idle_timeout, which is the number of seconds after which an inactive process will be aborted.

Let's say our server has two CPUs, each with four cores, and 8GB of RAM. Assuming Linux and its daemons are using around 2GB (use free -hlto get a more specific value), this leaves us around 6192MB.

Now, how much memory does each process use? To calculate this, there is a Python script called ps_mem.py . After running it, using sudo python ps_mem.py | grep php-fpm, you will get output similar to the following:

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

The first column is private memory. The second column is shared memory. The third column is the total RAM used. The fourth column is the name of the process.

From the above, you can see that the process size is 62,2 MiB. So, putting all this information into our formula, we come to the following:

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

Based on this, we come to the following setting values:

Setting Value
max_children 100
start_server 32
min_spare_servers 16
max_spare_servers 32

We will leave pm.process_idle_timeoutthe default of 10s. Assuming we are happy with these settings, we would configure it 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 

You can also regularly use memory monitoring tools to monitor how much memory your application is using. There are a number of options available for PHP, including php-memprof.

PHP in Ondemand mode

The ondemand method launches PHP-FPM fork processes when requests are received. To configure PHP-FPM in ondemand mode, you need to set the following parameters:

  • pm.max_children
  • pm.process_idle_timeout
  • pm.max_requests

pm.max_requests sets the number of requests each child process must execute before respawning. The documentation suggests that this setting is useful for getting around memory leaks.

Assuming you use the same settings as dynamic, we would configure it 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 ”, As it always depends on the type of applications you are running. However, here are some tips on which configuration to choose.

Low traffic site

If you have a low-traffic site, such as one that hosts a back-end control panel, such as cPanel , use ondemand. The memory will be saved as child processes will only be spawned when they are needed and killed when they are no longer needed. Since this is a backend, users can wait an extra moment or two while a thread is spawned to handle their request.

However, the spawn of a process is not "immediate" and therefore if you try to obtain maximum performance and earn even a few milliseconds the ondemand mode is certainly the least performing of the three available.

High traffic site

If you have a high traffic website, it is advisable to use the mode static and adjust the settings based on your needs over time and available hardware resources. It may seem overwhelming to have a large number of child processes always ready to receive requests, but for high-traffic sites it is essential that responses are fast and immediate.

High traffic sites need to respond as quickly as possible. Therefore, it is essential to use static so that a sufficient number of child processes are always ready to handle incoming requests. This approach ensures fast response times, improving user experience and reducing the risk of server overload.

Using the mode ondemand, child processes may consume too much memory due to continuous generation and termination, and the delay in starting processes may result in significant performance degradation. This behavior is generally unacceptable for high-traffic sites, where every millisecond counts.

The mode dynamic may represent a compromise, depending on your specific configuration. In some cases, it may offer sufficient performance, but you may end up with a configuration that, in fact, mirrors the mode static. The choice of mode depends on the specific characteristics of the site and the resources available, but to optimize the performance of high-traffic sites, static it often remains the best choice.

Using multiple pools per frontend / backend

Now one last recommendation: Serve your website's front end and back end using different pools .

Suppose you have an e-commerce site, perhaps powered by Magento or WooCommerce You can consider the application as consisting of two parts:

  • A frontend where customers can browse and make purchases
  • A backend, where the administrative staff manages the store (for example adding / removing products , category e tag e reviewing the ratings )

When viewed this way, it makes sense to have one pool serving the front end and another serving the back end and configuring them appropriately.

For what it's worth, you can split any application into multiple parts using this strategy if it makes sense to do so. Here's how to do it.

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

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

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

This creates two pools, one for the front end and one for the back end. They both have the same user and group, but have different process manager configurations and are connected through different sockets.

The frontend pool uses a static configuration with a small maximum number of child processes. The backend pool uses the ondemand configuration, even with a small number of configurations. These numbers are arbitrary, as they are for the purpose of an example.

With that saved, for your NGINX vhost file, you could for example 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 creates a virtual host configuration that sends requests to the front-end or back-end pool, based on the requested location. All requests /apithey are sent to the backend pool and all other requests are routed to the front end.


This was a quick introduction to optimizing PHP-FPM for better performance. We've looked at the three different process manager configurations, their settings, and discussed when each configuration makes sense. We then ended up looking at the workers pools.

We can briefly summarize that when it comes to PHP-FPM, once you start serving heavy traffic, dynamic and ondemand process managers for PHP-FPM can throttle throughput due to inherent overhead. Know your system and set your PHP-FPM processes to match your server's maximum capacity. To start withpm.max_childrenset to the maximum usage of pm dynamic or ondemand and then increase to the point where memory and CPU can process without being overloaded. You will notice that with pm static, (since you keep everything in memory) traffic spikes over time cause fewer CPU spikes and your server load and CPU averages will be smoother.

Updated: We have added A / B benchmark comparison chart. Having PHP-FPM processes in memory helps performance at the price of using more memory to keep them waiting.

benchmark php fpm static dynamic on demand

In case you are looking for an ad hoc and detailed tuning of the PHP interpreter, we can offer this personalized service to best optimize the performance of your site. Contact us for a detailed consultation and find out how we can help you significantly improve the speed and efficiency of your PHP environment.


Do you have doubts? Don't know where to start? Contact us!

We have all the answers to your questions to help you make the right choice.

Chat with us

Chat directly with our presales support.


Contact us by phone during office hours 9:30 - 19:30

Contact us online

Open a request directly in the contact area.


Managed Server Srl is a leading Italian player in providing advanced GNU/Linux system solutions oriented towards high performance. With a low-cost and predictable subscription model, we ensure that our customers have access to advanced technologies in hosting, dedicated servers and cloud services. In addition to this, we offer systems consultancy on Linux systems and specialized maintenance in DBMS, IT Security, Cloud and much more. We stand out for our expertise in hosting leading Open Source CMS such as WordPress, WooCommerce, Drupal, Prestashop, Joomla, OpenCart and Magento, supported by a high-level support and consultancy service suitable for Public Administration, SMEs and any size.

Red Hat, Inc. owns the rights to Red Hat®, RHEL®, RedHat Linux®, and CentOS®; AlmaLinux™ is a trademark of AlmaLinux OS Foundation; Rocky Linux® is a registered trademark of the Rocky Linux Foundation; SUSE® is a registered trademark of SUSE LLC; Canonical Ltd. owns the rights to Ubuntu®; Software in the Public Interest, Inc. holds the rights to Debian®; Linus Torvalds holds the rights to Linux®; FreeBSD® is a registered trademark of The FreeBSD Foundation; NetBSD® is a registered trademark of The NetBSD Foundation; OpenBSD® is a registered trademark of Theo de Raadt. Oracle Corporation owns the rights to Oracle®, MySQL®, and MyRocks®; Percona® is a registered trademark of Percona LLC; MariaDB® is a registered trademark of MariaDB Corporation Ab; REDIS® is a registered trademark of Redis Labs Ltd. F5 Networks, Inc. owns the rights to NGINX® and NGINX Plus®; Varnish® is a registered trademark of Varnish Software AB. Adobe Inc. holds the rights to Magento®; PrestaShop® is a registered trademark of PrestaShop SA; OpenCart® is a registered trademark of OpenCart Limited. Automattic Inc. owns the rights to WordPress®, WooCommerce®, and JetPack®; Open Source Matters, Inc. owns the rights to Joomla®; Dries Buytaert holds the rights to Drupal®. Amazon Web Services, Inc. holds the rights to AWS®; Google LLC holds the rights to Google Cloud™ and Chrome™; Microsoft Corporation holds the rights to Microsoft®, Azure®, and Internet Explorer®; Mozilla Foundation owns the rights to Firefox®. Apache® is a registered trademark of The Apache Software Foundation; PHP® is a registered trademark of the PHP Group. CloudFlare® is a registered trademark of Cloudflare, Inc.; NETSCOUT® is a registered trademark of NETSCOUT Systems Inc.; ElasticSearch®, LogStash®, and Kibana® are registered trademarks of Elastic NV Hetzner Online GmbH owns the rights to Hetzner®; OVHcloud is a registered trademark of OVH Groupe SAS; cPanel®, LLC owns the rights to cPanel®; Plesk® is a registered trademark of Plesk International GmbH; Facebook, Inc. owns the rights to Facebook®. This site is not affiliated, sponsored or otherwise associated with any of the entities mentioned above and does not represent any of these entities in any way. All rights to the brands and product names mentioned are the property of their respective copyright holders. Any other trademarks mentioned belong to their registrants. MANAGED SERVER® is a trademark registered at European level by MANAGED SERVER SRL, Via Enzo Ferrari, 9, 62012 Civitanova Marche (MC), Italy.


Would you like to see how your WooCommerce runs on our systems without having to migrate anything? 

Enter the address of your WooCommerce site and you will get a navigable demonstration, without having to do absolutely anything and completely free.

No thanks, my customers prefer the slow site.
Back to top