Creating a separate PHP-FPM pool isolates one site or application from other PHP workloads that share the same master process. A dedicated pool can run under its own Unix user, expose its own socket or TCP listener, and keep request limits or logging choices separate from the default pool.

A pool is a named configuration section loaded by PHP-FPM when the main php-fpm.conf file includes the pool directory. Each pool needs a unique listen endpoint plus a valid process-manager definition, and php-fpm -tt resolves those values before a reload so configuration problems can be caught before traffic is pointed at the new backend.

Examples below use the common Ubuntu or Debian layout under

/etc/php/8.3/fpm/pool.d/

, but the same pool structure applies on other Linux packages with different paths and unit names. When a Unix socket is used, keep the socket path short and make its ownership or mode match the web-server account, otherwise PHP-FPM or the web server can fail before the new pool accepts requests.

Steps to create a PHP-FPM pool:

  1. Check the existing pool files and listener paths before choosing a new pool name and socket path.
    $ ls /etc/php/8.3/fpm/pool.d/*.conf
    /etc/php/8.3/fpm/pool.d/www.conf
    
    $ grep -H '^listen = ' /etc/php/8.3/fpm/pool.d/*.conf
    /etc/php/8.3/fpm/pool.d/www.conf:listen = /run/php/php8.3-fpm.sock

    Ubuntu and Debian packages commonly store pool files under /etc/php/<version>/fpm/pool.d. Fedora, Red Hat, and CentOS Stream usually use /etc/php-fpm.d instead, so reuse the active package layout instead of mixing paths from another distribution.

  2. Create a new pool file named after the application or site.
    $ sudo vi /etc/php/8.3/fpm/pool.d/billing.conf

    Keep the filename and the pool name aligned with the application so later status checks, log paths, and listener targets stay easy to recognize.

  3. Add the new pool definition with a unique section name and listener.
    [billing]
    user = billing
    group = billing
    listen = /run/php/billing.sock
    listen.owner = www-data
    listen.group = www-data
    listen.mode = 0660
    pm = ondemand
    pm.max_children = 10
    pm.process_idle_timeout = 10s

    The PHP manual marks listen, user, pm, and pm.max_children as mandatory pool directives. The ondemand example above also uses pm.process_idle_timeout, while pm = dynamic requires pm.start_servers, pm.min_spare_servers, and pm.max_spare_servers as well.

    Keep Unix-socket paths short. If the full socket path becomes too long, PHP-FPM can fail to bind the listener even when the pool syntax is otherwise valid.

  4. Test the full PHP-FPM configuration before reloading the service.
    $ sudo php-fpm8.3 -tt
    [26-Mar-2026 10:13:13] NOTICE: [billing]
    [26-Mar-2026 10:13:13] NOTICE:     user = billing
    [26-Mar-2026 10:13:13] NOTICE:     listen = /run/php/billing.sock
    [26-Mar-2026 10:13:13] NOTICE:     pm = ondemand
    [26-Mar-2026 10:13:13] NOTICE:     pm.max_children = 10
    [26-Mar-2026 10:13:13] NOTICE:     pm.process_idle_timeout = 10
    [... resolved pool settings omitted ...]
    [26-Mar-2026 10:13:13] NOTICE: configuration file /etc/php/8.3/fpm/php-fpm.conf test is successful

    Use the binary that matches the installed PHP branch, such as php-fpm8.4 on a newer Ubuntu or Debian host. RHEL-family packages commonly use the unversioned php-fpm -tt command.

    Do not reload the service until the configuration test is successful.

  5. Reload PHP-FPM so it reads the new pool file.
    $ sudo systemctl reload php8.3-fpm

    Replace php8.3-fpm with the installed unit name when the host uses another PHP branch or the unversioned php-fpm service.

  6. Confirm that PHP-FPM created the new listener after the reload.
    $ ls -l /run/php/billing.sock
    srw-rw---- 1 www-data www-data 0 Mar 26 10:13 /run/php/billing.sock

    If the pool listens on a TCP address instead of a Unix socket, verify the bound endpoint with ss -ltn instead of checking /run/php.

    The new pool stays unused until the web server or reverse proxy is pointed at this listener, so update that upstream target separately if requests still land on the default pool.