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.
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-fpmThe 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
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 error | memory_limit | Where it comes from |
|---|---|---|
| 41943040 | 40M | WordPress's own WP_MEMORY_LIMIT default |
| 67108864 | 64M | WordPress multisite's WP_MEMORY_LIMIT default |
| 134217728 | 128M | PHP's default (php.ini-production) |
| 268435456 | 256M | A common raised value; WordPress's admin default |
| 536870912 | 512M | Imports, image processing |
| 1073741824 | 1G | Usually 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 as | Configuration file | Apply changes with |
|---|---|---|
| PHP-FPM (nginx, or Apache with proxy_fcgi) | /etc/php/8.3/fpm/php.ini | systemctl restart php8.3-fpm |
| Apache mod_php | /etc/php/8.3/apache2/php.ini | systemctl restart apache2 |
| Command line, cron, Composer | /etc/php/8.3/cli/php.ini | Nothing: read at every start |
| Rocky, AlmaLinux (all of the above) | /etc/php.ini | systemctl restart php-fpm |
php --ini answers the question for the command line only:
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:
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.phpphpinfo() 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:
| Method | Scope | Takes effect |
|---|---|---|
| php.ini or a conf.d file | Every site on that PHP version | After restarting PHP-FPM or Apache |
php_admin_value | One PHP-FPM pool, often one site | After restarting PHP-FPM; the site cannot raise it |
.user.ini | One directory tree (FPM and CGI only) | Within 5 minutes (user_ini.cache_ttl) |
php_value in .htaccess | One directory (Apache mod_php only) | Next request |
ini_set() | One script | Immediately, unless php_admin_value fixed it |
WP_MEMORY_LIMIT | One WordPress site | Next request, via ini_set() |
In php.ini, or better a conf.d file
memory_limit = 256MPHP 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
php_admin_value[memory_limit] = 256MThis 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
memory_limit = 256MPHP-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
php_value memory_limit 256MThis 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()
// 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
define( 'WP_MEMORY_LIMIT', '256M' );
define( 'WP_MAX_MEMORY_LIMIT', '512M' ); // admin screens, image editingWordPress 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
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:
| System | PHP | Service |
|---|---|---|
| Debian 12 | 8.2 | php8.2-fpm |
| Debian 13 | 8.4 | php8.4-fpm |
| Ubuntu 24.04 | 8.3 | php8.3-fpm |
| Ubuntu 22.04 | 8.1 | php8.1-fpm |
| Rocky, AlmaLinux | per module stream | php-fpm |
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[21-Oct-2026 09:20:11] NOTICE: configuration file /etc/php/8.3/fpm/php-fpm.conf test is successfulA few things catch people here:
- There is no service called php.
systemctl restart phpfails withUnit 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_passor Apache handler names. Restart that one. - Reload works too.
systemctl reload php8.3-fpmmakes FPM start over with fresh workers and read php.ini again; the restart is the variant that works in every case. - Docker. The official
phpimages read extra files from/usr/local/etc/php/conf.d/. Mount amemory.inithere and restart the container. - Control panels. Plesk and similar panels write the PHP-FPM pool files themselves and overwrite hand edits. Set
memory_limitin 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:
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.confThen 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:
// 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’sget()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 withfopen()andfgets(), 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_limitunits, 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 againstmemory_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 = 500in 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.