Troubleshooting

Fix PHP "Allowed memory size exhausted" fatal error

PHP stops a script when it tries to allocate more memory than memory_limit allows. Find the script that hit the limit, raise the limit in the right place, and fix the cause.

IntermediateLinux server6 min read

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 root or a sudo user such as deploy.
  • 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:

Bash
php -v
ls /etc/php/
systemctl list-units --type=service | grep -i fpm

Replace 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.

Bash
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 2345

Convert 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:

INI
; /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.log

Create 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.

Bash
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
<?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:

INI
; /etc/php/8.3/fpm/pool.d/example.com.conf
php_admin_value[memory_limit] = 256M

For every site on the server, edit the FPM ini:

INI
; /etc/php/8.3/fpm/php.ini
memory_limit = 256M

For a site without access to the pool file, use .user.ini in the document root:

INI
; /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:

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:

Bash
sudo systemctl restart php8.3-fpm

Warning: 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 while loop 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:

PHP
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

  1. Reproduce the action that failed before.
  2. Watch the log while you do it:
Bash
tail -f /var/log/php/example.com-error.log
  1. Confirm the new limit is live:
Bash
curl -s https://example.com/info.php
  1. Watch real memory use on the server:
Bash
free -m
ps -o pid,rss,cmd -C php-fpm8.3 --sort=-rss | head

The 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_value wins. Run php-fpm8.3 -tt to test the config, and check the pool file for a second memory_limit line.
  • You get a blank page or 500 instead of the memory message. display_errors is 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 pass php -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_children and 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

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.