Troubleshooting

PHP memory limit: fix "Allowed memory size exhausted" and raise memory_limit

Fix "Allowed memory size of X bytes exhausted": find the php.ini PHP really uses, raise the PHP memory limit for FPM or WordPress and restart PHP-FPM.

Published ~9 min read
On this page

Short answer: Allowed memory size of 134217728 bytes exhausted means one PHP request used more memory than the PHP memory limit (the memory_limit setting) allows, here PHP’s default of 128M. Raise memory_limit in the configuration your website’s PHP really reads (for PHP-FPM that is the FPM php.ini or the pool file, not the command-line one), restart PHP-FPM, and check the new value through the web server. If a single request needs gigabytes, the limit is not the problem: the script is.

Debian · Ubuntu · PHP-FPM
ls /etc/php/                                   # which PHP version? (8.3 below)
echo 'memory_limit = 256M' | sudo tee /etc/php/8.3/fpm/conf.d/99-memory.ini
sudo php-fpm8.3 -t && sudo systemctl restart php8.3-fpm

The paths are those of the Debian and Ubuntu PHP packages; PHP is 8.2 on Debian 12, 8.4 on Debian 13 and 8.3 on Ubuntu 24.04, so adjust the version. The default values quoted below were read from the php.ini files in Debian 12’s PHP 8.2 packages; what each setting does follows the PHP manual.

What “Allowed memory size of X bytes exhausted” means

Example output · PHP-FPM error, as logged by nginx
2026/10/21 09:14:02 [error] 2101#2101: *5821 FastCGI sent in stderr: "PHP message: PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes) in /var/www/example.com/app/Import.php on line 88" while reading response header from upstream, client: 203.0.113.5, server: example.com, request: "POST /import HTTP/1.1", upstream: "fastcgi://unix:/run/php/php8.3-fpm.sock:", host: "example.com"

PHP counts the memory each request allocates. When an allocation would take it past memory_limit, PHP stops the script with a fatal error. The visitor sees a 500 Internal Server Error, a blank page, or in WordPress “There has been a critical error on this website”. The number is the limit in bytes:

Bytes in the errormemory_limitWhere it comes from
4194304040MWordPress's own WP_MEMORY_LIMIT default
6710886464MWordPress multisite's WP_MEMORY_LIMIT default
134217728128MPHP's default (php.ini-production)
268435456256MA common raised value; WordPress's admin default
536870912512MImports, image processing
10737418241GUsually a sign to look at the script

The second number, tried to allocate, tells you what kind of problem it is. A small value such as 20480 bytes means the request grew step by step and the last small allocation tipped it over: raising the limit may be the right fix. A huge value, say tried to allocate 805306376 bytes, means one single operation asked for hundreds of megabytes at once, typically reading a whole file or result set into memory. Raising the limit only moves that wall.

Which php.ini is PHP actually using?

This is where most fixes go wrong. Debian and Ubuntu keep a separate php.ini for each way PHP runs, and the command line reads a different one from your website:

PHP runs asConfiguration fileApply changes with
PHP-FPM (nginx, or Apache with proxy_fcgi)/etc/php/8.3/fpm/php.inisystemctl restart php8.3-fpm
Apache mod_php/etc/php/8.3/apache2/php.inisystemctl restart apache2
Command line, cron, Composer/etc/php/8.3/cli/php.iniNothing: read at every start
Rocky, AlmaLinux (all of the above)/etc/php.inisystemctl restart php-fpm

php --ini answers the question for the command line only:

Example output · php --ini, Debian 12 layout
Configuration File (php.ini) Path: /etc/php/8.2/cli
Loaded Configuration File:         /etc/php/8.2/cli/php.ini
Scan for additional .ini files in: /etc/php/8.2/cli/conf.d
Additional .ini files parsed:      /etc/php/8.2/cli/conf.d/10-mysqlnd.ini,
/etc/php/8.2/cli/conf.d/10-opcache.ini,
/etc/php/8.2/cli/conf.d/10-pdo.ini,
/etc/php/8.2/cli/conf.d/20-calendar.ini,
...

That trips people up in both directions. Debian’s CLI php.ini ships with memory_limit = -1 (no limit), while the FPM and Apache files get 128M. So a script that runs fine with php script.php can die in the browser, and php -i | grep memory_limit prints -1 while the website is stuck at 128M. Ask the web server instead, with a one-line file you delete right after:

Debian · Ubuntu
echo '<?php echo ini_get("memory_limit"), PHP_EOL;' | sudo tee /var/www/example.com/mem-check.php > /dev/null
curl -s https://example.com/mem-check.php      # prints e.g. 128M
sudo rm /var/www/example.com/mem-check.php

phpinfo() does the same with more detail: its Local Value column is what the site gets after every override, Master Value is php.ini alone. Never leave a phpinfo file on a public site.

Where to set memory_limit

memory_limit may be changed anywhere, from php.ini down to a single script. Pick the narrowest place that covers what needs more memory:

MethodScopeTakes effect
php.ini or a conf.d fileEvery site on that PHP versionAfter restarting PHP-FPM or Apache
php_admin_valueOne PHP-FPM pool, often one siteAfter restarting PHP-FPM; the site cannot raise it
.user.iniOne directory tree (FPM and CGI only)Within 5 minutes (user_ini.cache_ttl)
php_value in .htaccessOne directory (Apache mod_php only)Next request
ini_set()One scriptImmediately, unless php_admin_value fixed it
WP_MEMORY_LIMITOne WordPress siteNext request, via ini_set()

In php.ini, or better a conf.d file

/etc/php/8.3/fpm/conf.d/99-memory.ini
memory_limit = 256M

PHP reads php.ini first and then every file in conf.d in alphabetical order, and a later value wins, so a 99- file overrides php.ini without touching it. A package upgrade that brings a new php.ini then cannot undo your change. Write the value as 256M: the PHP manual lists only K, M and G as units and says anything else is taken as bytes, so 256MB is not 256 megabytes.

In the PHP-FPM pool

/etc/php/8.3/fpm/pool.d/www.conf
php_admin_value[memory_limit] = 256M

This sets the limit for one pool only, which is the right level when each site has a pool of its own. php_admin_value fixes the value: per the PHP manual, the site’s code cannot change it with ini_set(). php_value sets the same default but lets the application raise it. If a .user.ini or a WordPress constant seems to do nothing, look for a php_admin_value in the pool first.

In .user.ini, without root access

/var/www/example.com/.user.ini
memory_limit = 256M

PHP-FPM reads .user.ini files from the requested script’s directory up to the document root. It caches them for user_ini.cache_ttl seconds, 300 by default, so allow up to five minutes. Apache with mod_php and the command line ignore these files.

In .htaccess, with Apache mod_php only

.htaccess
php_value memory_limit 256M

This works only while PHP runs inside Apache as mod_php. On a server where Apache hands PHP to PHP-FPM, the line itself is an error: Apache answers every request in that directory with a 500 and logs Invalid command 'php_value'. nginx never reads .htaccess at all.

At runtime with ini_set()

PHP
// at the top of a heavy import script, before the work starts
ini_set('memory_limit', '512M');

Raising the limit for the one script that needs it keeps every other request at a safe default. ini_set() returns the old value, or false if the change was refused, which is what happens under php_admin_value.

In WordPress: WP_MEMORY_LIMIT

wp-config.php · above "That's all, stop editing!"
define( 'WP_MEMORY_LIMIT', '256M' );
define( 'WP_MAX_MEMORY_LIMIT', '512M' );   // admin screens, image editing

WordPress uses ini_set() to raise PHP’s limit to WP_MEMORY_LIMIT (40M by default, 64M on multisite) and never lowers it. With PHP already at 128M the default does nothing, and with a pool’s php_admin_value no constant gets past it. Tools, Site Health, Info shows both values: PHP memory limit under Server and the constants under WordPress Constants.

On the command line and for Composer

any Linux
php -d memory_limit=1G bin/import.php
COMPOSER_MEMORY_LIMIT=-1 composer update

-d overrides one setting for one run. -1 means no limit at all, fine for a one-off command you are watching and never right for PHP-FPM, where one runaway request could then take all the RAM.

Restart PHP-FPM so the change takes effect

PHP-FPM reads php.ini and the pool files when it starts, so a change there needs a restart. The service carries the version in its name on Debian and Ubuntu:

SystemPHPService
Debian 128.2php8.2-fpm
Debian 138.4php8.4-fpm
Ubuntu 24.048.3php8.3-fpm
Ubuntu 22.048.1php8.1-fpm
Rocky, AlmaLinuxper module streamphp-fpm
Debian · Ubuntu
systemctl list-units --type=service 'php*'     # which FPM services exist
sudo php-fpm8.3 -t                             # check the FPM configuration
sudo systemctl restart php8.3-fpm
systemctl status php8.3-fpm --no-pager
Example output · php-fpm8.3 -t
[21-Oct-2026 09:20:11] NOTICE: configuration file /etc/php/8.3/fpm/php-fpm.conf test is successful

A few things catch people here:

  • There is no service called php. systemctl restart php fails with Unit php.service not found. Use the FPM service, or restart Apache when PHP runs as mod_php. Command-line PHP needs no restart.
  • Several versions side by side. With PHP 8.2 and 8.3 installed, the site uses whichever socket its nginx fastcgi_pass or Apache handler names. Restart that one.
  • Reload works too. systemctl reload php8.3-fpm makes FPM start over with fresh workers and read php.ini again; the restart is the variant that works in every case.
  • Docker. The official php images read extra files from /usr/local/etc/php/conf.d/. Mount a memory.ini there and restart the container.
  • Control panels. Plesk and similar panels write the PHP-FPM pool files themselves and overwrite hand edits. Set memory_limit in the domain’s PHP settings in the panel, which applies it for you.

Then run the check file from above again. If it still prints the old value, the change went into a file this PHP does not read, or a php_admin_value overrides it.

How high should memory_limit be?

memory_limit is a ceiling per request, not memory PHP reserves. What the server needs is what the workers really use, times how many run at once. Measure it on the live server:

Debian · Ubuntu
ps --no-headers -o rss -C php-fpm8.3 | awk '{s+=$1; n++} END {printf "%d processes, average %.0f MB\n", n, s/n/1024}'
grep -E '^pm(\.max_children)? ' /etc/php/8.3/fpm/pool.d/www.conf

Then check that the pool fits: pm.max_children times the average worker size, plus the database and the system, must stay below the RAM. Take a 2 GB server with MariaDB using 400 MB and the system 300 MB: about 1.3 GB is left for PHP. With workers averaging 80 MB, that is room for about 15 children. A memory_limit of 256M is still fine there, because only the odd heavy request gets near it. Fifteen requests at 256M at the same moment would need 3.75 GB, and the kernel’s OOM killer would step in. Set memory_limit for the heaviest legitimate request and pm.max_children for the typical one; a pool that is too small for the traffic shows up as a 503 Service Unavailable instead.

When raising the limit hides a leak

If you have doubled the limit twice and the error comes back at the same line, stop raising it. Find out how much the request really needs:

PHP
// at the end of the request, or around the suspect block
error_log(sprintf('peak memory: %.1f MB', memory_get_peak_usage(true) / 1048576));

The usual causes, and what fixes them better than a bigger number:

  • A whole result set in an array. fetchAll() or an ORM’s get() on a large table loads every row at once. Iterate row by row, or process the table in chunks of a few thousand.
  • A whole file in a string. file_get_contents() on a 500 MB export needs at least 500 MB. Read it line by line with fopen() and fgets(), or stream it.
  • Image processing. GD keeps a true-colour image decoded in memory at 4 bytes per pixel. A 6000 × 4000 photo takes 96,000,000 bytes, about 92M in memory_limit units, however small the JPEG file is, and every resized copy adds more. With the GD bundled in PHP (the official Docker images, for example) that counts against memory_limit; Debian and Ubuntu link the system libgd, so there it comes out of the server’s RAM instead. Limit the pixel size of uploads, or create thumbnails in a background job.
  • A loop or recursion that never ends. Code that appends to an array forever exhausts any limit. A higher one just makes it fail later and use more RAM on the way.
  • Long-running workers. Queue consumers and daemons grow over hours. Restart them after a number of jobs (most frameworks have an option for it), and set pm.max_requests = 500 in the FPM pool, so each worker is replaced after 500 requests and a slow leak in an extension never builds up.

On your own server

On shared hosting the provider often fixes memory_limit with php_admin_value, which is why .user.ini and WordPress constants do nothing there. On a VPS you control every layer above, and the only limit you cannot configure away is the RAM itself. If the measured numbers do not fit, a bigger plan is the fix: on a VMHeaven VPS, an upgrade from the panel adds RAM to the same server, your data and IP address stay, and the new resources apply after a reboot. Until then, swap buys headroom against the OOM killer, not speed.

Frequently asked

What is the default PHP memory limit?

128M, which is 134217728 bytes, as set in php.ini-production. Debian and Ubuntu use it for PHP-FPM and Apache, but their command-line php.ini sets memory_limit = -1, no limit at all, so a script can run fine with php on the command line and still fail on the website.

How do I restart PHP-FPM?

On Debian and Ubuntu the service name carries the PHP version: sudo systemctl restart php8.3-fpm on Ubuntu 24.04, php8.2-fpm on Debian 12 and php8.4-fpm on Debian 13. On Rocky Linux and AlmaLinux it is sudo systemctl restart php-fpm. systemctl list-units --type=service 'php*' lists the ones installed, and sudo php-fpm8.3 -t checks the configuration before the restart.

How do I increase the memory limit in WordPress?

Add define( 'WP_MEMORY_LIMIT', '256M' ); to wp-config.php above the line "That's all, stop editing!". WordPress raises PHP's limit with ini_set() but never lowers it, and it cannot get past a php_admin_value set in the PHP-FPM pool. In that case raise the limit in the pool file or php.ini and restart PHP-FPM.

Why did changing memory_limit in php.ini change nothing?

Usually it went into the wrong file: on Debian and Ubuntu the command line, PHP-FPM and Apache each read their own php.ini, and php --ini only shows the command-line one. Check the value the website gets with ini_get('memory_limit') in a temporary file, make sure PHP-FPM was restarted, and look for a php_admin_value in the pool file that overrides it.

Related articles

All troubleshooting