PHP stops a script the moment it tries to allocate more memory than memory_limit allows, and the request dies with a fatal error. In this guide you will find the exact file and line that hit the limit, raise the limit in the right place, and then fix the loop or leak that caused it.
Before you start
You need:
- SSH access to your Linux VPS as
rootor a sudo user such asdeploy. - The name of the site that fails, for example
example.com. - Permission to restart PHP-FPM — this briefly drops in-flight requests.
- A way to reproduce the error, or a recent timestamp from the logs.
Confirm your PHP version and service name first, because the paths below include the version number:
php -v
ls /etc/php/
systemctl list-units --type=service | grep -i fpmReplace 8.3 in every path with the version you actually run.
Read the error and find the script
The fatal error names the file and line. Start with the web server and PHP logs.
tail -n 200 /var/log/nginx/error.log
tail -n 200 /var/log/php8.3-fpm.log
journalctl -u php8.3-fpm --since "1 hour ago"A typical line looks like this:
PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes) in /var/www/example.com/wp-includes/class-wpdb.php on line 2345Convert the byte count to something readable: 134217728 bytes is 128M, 268435456 is 256M. The path after "in" is the script that ran out of memory. That path tells you whether the problem is core code, a plugin, or your own application.
If the log does not show the file, turn on PHP error logging for that pool:
; /etc/php/8.3/fpm/pool.d/example.com.conf
php_admin_flag[log_errors] = on
php_admin_value[error_log] = /var/log/php/example.com-error.logCreate the directory first with mkdir -p /var/log/php and give the FPM user write access, then reload PHP-FPM.
Check the limit that actually applies
PHP reads several ini files, and the CLI value is usually not the one your website uses. Check each one.
php -r 'echo ini_get("memory_limit"), PHP_EOL;' # CLI
grep -R "memory_limit" /etc/php/8.3/fpm/ /etc/php/8.3/cli/Then check the value the web request sees. Create a temporary file in the site root:
<?php
// /var/www/example.com/info.php
echo ini_get('memory_limit'), PHP_EOL;
echo ini_get('max_execution_time'), PHP_EOL;Open https://example.com/info.php, note the value, then delete the file. Leaving it in place exposes server details.
Warning: php_admin_value set in a pool file cannot be changed by ini_set or WP_MEMORY_LIMIT. If you raise the limit in wp-config.php and nothing changes, the pool file is overriding you.
Raise memory_limit in the right place
Pick the narrowest scope that solves the problem.
For one site only, edit its pool file:
; /etc/php/8.3/fpm/pool.d/example.com.conf
php_admin_value[memory_limit] = 256MFor every site on the server, edit the FPM ini:
; /etc/php/8.3/fpm/php.ini
memory_limit = 256MFor a site without access to the pool file, use .user.ini in the document root:
; /var/www/example.com/.user.ini
memory_limit = 256M.user.ini is cached for a few minutes by default, so give it time or restart PHP-FPM. It does not apply to CLI scripts.
For WordPress specifically, you can also add to wp-config.php:
define('WP_MEMORY_LIMIT', '256M');
define('WP_MAX_MEMORY_LIMIT', '512M');WP_MAX_MEMORY_LIMIT covers admin and image work. WordPress can raise the limit but never lower it.
Apply the change:
sudo systemctl restart php8.3-fpmWarning: Restarting PHP-FPM drops requests that are being processed right now. Do it during a quiet period, and use reload instead of restart if you only changed ini values.
Do not jump straight to -1 (unlimited). A runaway script with no limit can take the whole VPS down instead of failing on its own.
Fix the cause: leaks and loops
Raising the limit buys time. If the number keeps climbing, find the reason.
- Unbounded loops and recursion. A
whileloop waiting on a condition that never becomes true, or a recursive function without a depth check, grows until PHP stops it. Add a counter and a hard exit. - Large result sets. Loading 200,000 rows into an array uses far more memory than the rows themselves. Add
LIMIT, paginate, and use unbuffered queries for exports. See Find slow queries in MySQL with the slow query log. - Image processing. GD and Imagick hold a full decoded bitmap in memory, which is many times the file size. Cap upload dimensions and set a higher limit for the image path only.
- Plugins and themes. On WordPress, deactivate plugins one at a time and switch to a default theme to isolate the offender.
- Xdebug in production. The profiler adds a large overhead. Remove or disable it on live servers.
To measure a single script, log the peak:
register_shutdown_function(function () {
error_log(sprintf('peak memory: %.2f MB', memory_get_peak_usage(true) / 1048576));
});For long-running workers and queue consumers, memory grows over hours. Restart them on a schedule or after a fixed number of jobs.
Check it works
- Reproduce the action that failed before.
- Watch the log while you do it:
tail -f /var/log/php/example.com-error.log- Confirm the new limit is live:
curl -s https://example.com/info.php- Watch real memory use on the server:
free -m
ps -o pid,rss,cmd -C php-fpm8.3 --sort=-rss | headThe page should load without a fatal error, and PHP-FPM child processes should stay well below the server's total RAM. If memory is tight, tune the pool before raising limits further — see Tune PHP-FPM pools for your RAM.
Troubleshooting
- The error still appears after you raised the limit. You edited the wrong ini file, or the pool's
php_admin_valuewins. Runphp-fpm8.3 -ttto test the config, and check the pool file for a secondmemory_limitline. - You get a blank page or 500 instead of the memory message.
display_errorsis off, which is correct on production. Read the error log instead of the browser. - A CLI script still fails. CLI has its own ini file at
/etc/php/8.3/cli/php.ini. Set the limit there, or passphp -d memory_limit=512M script.php. - The OOM killer terminates MySQL or PHP-FPM. The server ran out of RAM, not the script. Reduce
pm.max_childrenand check Tune MySQL and MariaDB memory for a VPS. - Memory climbs slowly until the site is restarted. That is a leak, not a limit problem. Use the peak-memory logging above to find the script, and restart the worker in the meantime.
Next steps
- Tune PHP-FPM pools (pm.max_children) for your RAM
- Monitor CPU, memory, disk and logs on a Linux server
- Read and manage Nginx access and error logs
- Find slow queries in MySQL with the slow query log
- Need more RAM for the same workload? Compare [Linux VPS plans](/
