Showing PHP warnings and fatal errors makes debugging faster when a request fails, an include breaks, or a runtime change stops the application from starting. Hiding that same output matters on internet-facing systems because visible diagnostics can leak stack traces, filesystem paths, SQL fragments, and other internal details that belong in operator tooling instead of the response body.
PHP separates error generation from error display. error_reporting defines which severities are raised, display_errors and display_startup_errors control whether the client sees them, and log_errors keeps the same events available to operators. On PHP-FPM hosts, the final value can also be changed after php.ini by pool-level php_value[] or php_admin_value[] directives, FastCGI PHP_VALUE or PHP_ADMIN_VALUE headers, or a local .user.ini file.
Examples below use the packaged PHP-FPM layout common on current Ubuntu or Debian systems. Replace the sample binary name, service unit, and path with the branch that actually serves the application, keep log_errors enabled when output is hidden, and validate the configuration before reloading so a display-setting change does not become an outage.
$ php-fpm8.3 -i | grep -E '^(Loaded Configuration File|display_errors =>|display_startup_errors =>|error_reporting =>|log_errors =>)' Loaded Configuration File => /etc/php/8.3/fpm/php.ini display_errors => Off => Off display_startup_errors => Off => Off error_reporting => 32767 => 32767 log_errors => On => On
Use the binary that matches the deployed runtime. php --ini reports only the CLI configuration, which is often different from PHP-FPM or an Apache module.
Related: How to find PHP configuration files
$ sudo cp /etc/php/8.3/fpm/php.ini /etc/php/8.3/fpm/php.ini.bak-$(date +%Y%m%d%H%M%S)
$ sudo vi /etc/php/8.3/fpm/php.ini
Replace the sample path with the file reported in the first step when the runtime uses a different PHP branch, layout, or SAPI.
Related: How to find PHP configuration files
display_errors = On display_startup_errors = On error_reporting = E_ALL log_errors = On
error_reporting = -1 is equivalent to E_ALL and keeps future error levels included as well.
Do not leave display_errors = On enabled on a public application after the debugging session is complete.
display_errors = Off display_startup_errors = Off error_reporting = E_ALL log_errors = On
Keeping error_reporting = E_ALL with log_errors = On hides the warning from the client without discarding the event from logs.
Setting error_reporting = 0 suppresses useful diagnostics instead of only hiding them from the response.
$ sudo php-fpm8.3 -tt [25-Mar-2026 22:59:16] NOTICE: configuration file /etc/php/8.3/fpm/php-fpm.conf test is successful
Use php-fpm -tt on systems that provide an unversioned binary. The -tt option prints the resolved PHP-FPM configuration as well as the final syntax result.
Do not reload the service until the configuration test succeeds.
$ sudo systemctl reload php8.3-fpm
When PHP runs as an Apache module, reload the web server instead, such as sudo systemctl reload apache2 or sudo systemctl reload httpd. On .user.ini-based deployments, the new value normally appears after the user_ini.cache_ttl interval rather than a service reload.
$ sudo tee /var/www/example.com/public/php-warning-check.php >/dev/null <<'PHP'
<?php
trigger_error('display probe', E_USER_WARNING);
echo "probe complete", PHP_EOL;
PHP
Replace /var/www/example.com/public with the real document root for the site or pool that uses the edited runtime.
Remove the probe file after the visible or hidden warning output is confirmed so a diagnostic endpoint is not left exposed.
$ curl -s http://example.com/php-warning-check.php Warning: display probe in /var/www/example.com/public/php-warning-check.php on line 2 probe complete
With the debugging profile, the warning should appear before probe complete. With the production profile, the same request should return only probe complete while the warning is still logged. If the site is only reachable through HTTPS, a local vhost name, or an internal reverse proxy, use that exact URL instead of the example host.
$ sudo rm /var/www/example.com/public/php-warning-check.php
$ sudo grep -REn 'php_(admin_)?(flag|value)\[(display_errors|display_startup_errors|error_reporting|log_errors|error_log)\]|PHP_(ADMIN_)?VALUE' /etc/php/8.3/fpm/pool.d /etc/php-fpm.d /etc/apache2 /etc/httpd /etc/nginx 2>/dev/null /etc/php/8.3/fpm/pool.d/www.conf:490:php_admin_flag[display_errors] = off
PHP-FPM pool files can override the global php.ini with php_flag[], php_value[], php_admin_flag[], or php_admin_value[]. FastCGI PHP_VALUE and PHP_ADMIN_VALUE parameters can do the same in the web-server configuration.
Settings forced with php_admin_value[] or php_admin_flag[] cannot be changed later with ini_set().
$ find /var/www/example.com -name .user.ini -print /var/www/example.com/public/.user.ini
These files are ignored when PHP runs as an Apache module. On CGI and FastCGI deployments, changes are re-read on the user_ini.cache_ttl interval instead of immediately.