PHP Configuration: php.ini, FPM, and Per-Directory Files

Published Updated

PHP configuration controls runtime behavior such as error reporting, memory limits, upload limits, timeouts, and extension settings. Old tutorials often treated one php.ini file as the whole system, while current deployments may add PHP-FPM pools, scanned INI files, containers, managed-host settings, and per-directory overrides.

Before editing a setting, find the configuration files loaded by the PHP process serving your application. The command line and web server may use different files, which explains why a change can work in one place and appear to do nothing in another.

Identify the SAPI

A SAPI (Server Application Programming Interface) is PHP's interface to the environment running it. CLI, PHP-FPM, the Apache module, and CGI-style installations can load different files or read them at different times.

Ask the command-line binary which configuration it loaded:

$ php --ini
Configuration File (php.ini) Path: /etc/php/8.5/cli
Loaded Configuration File:         /etc/php/8.5/cli/php.ini
Scan for additional .ini files in: /etc/php/8.5/cli/conf.d

The output identifies the configuration files used by command-line PHP. It does not prove that a web request uses the same path because PHP-FPM may run another binary, pool, chroot, or container image.

For a temporary local web diagnostic, print the SAPI and loaded file through the actual request path:

<?php
header("Content-Type: text/plain");

echo "SAPI: ", PHP_SAPI, PHP_EOL;
echo "php.ini: ", php_ini_loaded_file() ?: "none", PHP_EOL;

Request the file through the web server, record the result, and delete it. A public diagnostic endpoint exposes runtime details that should remain private.

How Do PHP Configuration Files Override Each Other?

PHP reads the base configuration first, then scanned files in their load order. A PHP-FPM pool or web-server directive can override allowed values for that request environment. A .user.ini file may add per-directory values for CGI and FastCGI SAPIs, and ini_set() can change runtime-modifiable directives for one script.

The last permitted override determines the effective value. A php_admin_value in an FPM pool is stronger than an ordinary script setting, so ini_set() cannot override it later.

Edit the Main php.ini File

The main php.ini file supplies the base runtime configuration. The following example makes error handling and resource limits explicit. Adjust these limits and the time zone for your application; they are not universal production settings:

display_errors = Off
log_errors = On
error_log = /var/log/php/error.log
memory_limit = 256M
upload_max_filesize = 16M
post_max_size = 20M
date.timezone = Australia/Melbourne

post_max_size must leave room for the entire request body, so it normally needs to be larger than upload_max_filesize. Keep application secrets out of this file. Database passwords, API tokens, and signing keys belong in deployment-controlled environment variables or a secret manager.

Restart PHP-FPM and Verify the Change

PHP reads php.ini when the process starts. A long-running PHP-FPM service therefore needs a restart or reload before web requests see the edited value. The service name depends on the operating system package; this Debian or Ubuntu example uses the PHP 8.5 service:

sudo systemctl restart php8.5-fpm
systemctl is-active php8.5-fpm

active

The final active output confirms that FPM is running. Check that the restart command succeeded, then use the diagnostic page to confirm the effective setting. Check the same SAPI that serves the application because a successful CLI command only confirms the CLI configuration.

Scanned Configuration Files

Many installations split configuration across a base file and fragments in a conf.d directory. PHP scans files ending in .ini in alphabetical order, so a later fragment can override an earlier setting.

; 90-app-production.ini
display_errors = Off
log_errors = On
memory_limit = 256M
max_execution_time = 30

An environment-specific fragment keeps application runtime choices visible without editing a distribution file that a package or image update may replace. Use php --ini or php_ini_scanned_files() to see the loaded order to identify which file supplied the setting.

Web Server and Pool Settings

PHP-FPM pools can set values for one site or service. The php_admin_value form prevents a script from overriding the deployment limit:

; www.conf
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 16M
php_value[post_max_size] = 20M

Apache module deployments may set PHP directives in virtual-host or .htaccess configuration. Do not assume those files affect PHP-FPM, nginx, or a managed host. The LAMP stack guide explains how the web server hands requests to PHP.

Per-Directory .user.ini Files

CGI and FastCGI SAPIs, including PHP-FPM, can read per-directory .user.ini files. They help on hosts that allow application-specific values without access to the service configuration.

upload_max_filesize = 16M
post_max_size = 20M
max_execution_time = 30

PHP caches these files according to user_ini.cache_ttl, so a changed value may stay stale until the cache expires. Keep the file away from user-writable upload directories and remember that it can change only directives permitted at the per-directory level.

Script-Level Overrides

ini_set() changes an allowed directive for the current script. It can suit one specific import or report that needs a different limit:

<?php

$previousLimit = ini_set("memory_limit", "512M");

if ($previousLimit === false) {
    throw new RuntimeException("memory_limit cannot be changed");
}

The return value is the previous setting as a string, or false when the option does not exist or cannot be changed. Shared error behavior, upload ceilings, and timeout policy belong in the runtime layer where operators can audit them.

Development and Production Settings

SettingDevelopmentProduction
display_errorsOnOff
log_errorsOnOn
error_reportingBroadBroad
upload_max_filesizeClose to productionDocumented limit
memory_limitClose to productionDocumented limit

Development can display more detail, but resource limits should stay close enough to production that uploads and imports fail during testing instead of after deployment. The PHP security guide covers the related checks for uploads, sessions, and error handling.

Common Pitfalls & Debugging

A Value Stays Stale After an Edit

Symptom: the diagnostic page shows the old value after php.ini changes. Cause: the wrong file was edited, a later scanned file overrode the value, or the serving process did not reload. Fix: inspect the web SAPI's loaded file and scanned list, restart the correct FPM or Apache service, then request the diagnostic again.

CLI and FPM Show Different Values

Symptom: php -i reports one limit while the web application reports another. Cause: CLI and FPM can load different configuration files. Fix: compare php --ini with php_ini_loaded_file() through the web request, then edit and reload the SAPI that owns the failing code.

Production Displays Error Details

Symptom: a failed request prints a stack trace or filesystem path in the browser. Cause: display_errors is enabled in a production layer. Fix: turn display off at the production runtime layer, keep log_errors on, verify the log destination, and return a safe response.

Frequently Asked Questions

How can you find the loaded php.ini file?

The php --ini command identifies the php.ini file loaded by command-line PHP. For a web request, inspect php_ini_loaded_file() or a temporary phpinfo() page through the same web server and PHP-FPM pool that serves the application. Delete any public diagnostic page after recording the result.

Does every php.ini change require a restart?

A long-running server SAPI must reload its configuration before it sees a changed php.ini file. Restart or reload PHP-FPM for FPM requests, or reload Apache when PHP runs as an Apache module. CLI reads configuration when each command starts, so the next command sees the change.

Can ini_set() change every PHP directive?

PHP ini_set() can change only directives that allow runtime changes. Some directives can change inside a script, while system-level or php_admin_value settings cannot. Check the directive's documented change mode before relying on ini_set().

Should display_errors be enabled in production?

PHP display_errors should be disabled in production because displayed errors can expose filesystem paths, queries, configuration, and other application details. Keep display_errors available only in a private development environment and confirm that log_errors sends the full diagnostic to an operator.

Can a per-directory .user.ini setting override a php_admin_value set in the FPM pool?

A .user.ini file cannot override a PHP-FPM setting defined with php_admin_value. Use ordinary php_value in the pool when a directory-level .user.ini file should still be allowed to override the setting.

Sources

  1. [1]
  2. [2]
  3. [3]
  4. [4]
  5. [5]
    ini_set
    (php.net)
  6. [6]