The Fatal error: Allowed memory size of N bytes exhausted error means the script tried to allocate more memory than the PHP memory_limit directive permits. The fix is to raise that limit — but where you raise it depends on which PHP runtime (web SAPI, FPM pool, or CLI) you're hitting and how your app is deployed (Apache + mod_php, Nginx + PHP-FPM, command-line cron, Composer, WordPress, Laravel artisan). Below: every override mechanism in order from "single script" to "server-wide", with the modern PHP 8.x defaults, the OPcache caveat that explains why your php.ini change "doesn't take effect", and the specific patterns for Composer out-of-memory, PHPUnit, WP-CLI, and Laravel artisan migrations.
What is the PHP memory_limit and how do I increase it?
The PHP memory_limit is the maximum amount of memory a single PHP script is allowed to allocate. The PHP 8.x default is 128M (changed from -1/unlimited in older versions). When a script exceeds it, PHP emits Fatal error: Allowed memory size of N bytes exhausted (tried to allocate X bytes) and terminates. To raise the limit you can: set memory_limit = 256M in php.ini (server-wide), ini_set('memory_limit', '256M') at the top of a PHP file (per-script), php_value memory_limit 256M in .htaccess (per-directory under Apache), php_admin_value[memory_limit] = 256M in a PHP-FPM pool config (per-pool under Nginx/FPM), or php -d memory_limit=256M script.php on the command line. The most-common-by-runtime: php.ini for web SAPI, FPM pool config for production FPM, the -d flag for one-off CLI invocations.
Set your target memory limit, PHP version, and the script name once. Shell and config examples below update so you can copy and run.
Jump to:
- PHP 8.x defaults and shorthand
- Find the right php.ini
- Method 1: php.ini (server-wide)
- Method 2: ini_set() in PHP code (per-script)
- Method 3: .htaccess (Apache, per-directory)
- Method 4: PHP-FPM pool config (Nginx)
- Method 5: php -d flag (one-off CLI)
- Method 6: WordPress wp-config.php
- Method 7: Docker / containers
- Common out-of-memory patterns
- Verify the change took effect
- Troubleshooting: why your change didn't apply
- FAQ
PHP 8.x defaults and shorthand
| Setting | Default in PHP 8.x | Notes |
|---|---|---|
memory_limit (web SAPI) | 128M | Set in the bundled php.ini-production |
memory_limit (CLI SAPI) | 128M | Set in php-cli.ini on Debian-family distros |
-1 (unlimited) | not the default | Was the default in PHP 5.0; valid since PHP 5.1.0 |
PHP accepts shorthand suffixes (since 5.1.0, current in every supported version):
Kork— kibibytes (1024 bytes)Morm— mebibytesGorg— gibibytes- No suffix — bytes
So 1G, 1024M, 1048576K, and 1073741824 are all equivalent. 1G is the readable form.
memory_limit = -1 means unlimited (let the OS decide). Useful for Composer or PHPUnit but never for web-facing PHP — a runaway script can starve the entire server.
Find the right php.ini
Before editing anything, find which php.ini is actually loaded — this is the source of "I changed it but nothing happened" half the time.
# From CLI
php --ini
# Output:
# Configuration File (php.ini) Path: /etc/php/:php_version/cli
# Loaded Configuration File: /etc/php/:php_version/cli/php.ini
# Scan for additional .ini files in: /etc/php/:php_version/cli/conf.d
# Additional .ini files parsed: /etc/php/:php_version/cli/conf.d/10-mysqlnd.ini, ...For the web SAPI (the one your browser hits), put <?php phpinfo(); in a test file, load it through the web server, and look for "Loaded Configuration File". It's almost always a DIFFERENT file from the CLI php.ini — e.g., /etc/php/8.4/fpm/php.ini for FPM, /etc/php/8.4/apache2/php.ini for mod_php.
Edit the right one. On most Debian/Ubuntu setups there are at least two (cli + fpm or cli + apache2). On Docker, the file is typically inside the container at /usr/local/etc/php/php.ini.
Method 1: php.ini (server-wide)
The canonical way. Edit the loaded php.ini and set:
memory_limit = 256MThen reload the SAPI that's serving requests:
# Apache + mod_php
sudo systemctl reload apache2
# PHP-FPM (Nginx or Apache + FPM proxy)
sudo systemctl reload php:php_version-fpmCLI changes take effect on the next php invocation — no reload needed.
A subtle note: most production php.ini files inherit a memory_limit setting from /etc/php/8.4/{fpm,cli,apache2}/conf.d/*.ini snippets that are loaded after the main file. If your edit isn't taking effect, run php -i | grep memory_limit and check the "INI Files" line at the top to see the full include order.
Method 2: ini_set() in PHP code (per-script)
Add at the top of the script (before any allocations):
<?php
ini_set('memory_limit', '256M');
// ... rest of your scriptThis only affects the current script execution. Useful when one specific endpoint (image upload, CSV import, report generator) needs more memory than the global limit, without lifting the limit for every request.
It doesn't always work. If the host disabled ini_set for security reasons (some shared hosts do), or if memory_limit is in disable_functions / disable_classes exclusions, the call silently fails. Always check with phpinfo() or ini_get('memory_limit') after the call:
ini_set('memory_limit', '256M');
echo ini_get('memory_limit'); // should print "256M"For long-running scripts, raise the limit BEFORE the memory-heavy work — ini_set doesn't help after PHP has already raised the fatal error.
Method 3: .htaccess (Apache, per-directory)
Only works on Apache + mod_php (not FPM). Add to .htaccess in your document root or a specific subdirectory:
php_value memory_limit 256MThe setting cascades into subdirectories. If you need to combine with other PHP overrides:
php_value memory_limit 256M
php_value upload_max_filesize 32M
php_value post_max_size 32M
php_value max_execution_time 300This silently fails under PHP-FPM because FPM doesn't read .htaccess. If you're on Nginx + FPM, use Method 4 instead. If you're on Apache + FPM (the modern Apache default), also use Method 4.
Method 4: PHP-FPM pool config (Nginx)
The right way for modern Nginx + FPM stacks. Find the pool config — typically /etc/php/8.4/fpm/pool.d/www.conf. Add or modify:
php_admin_value[memory_limit] = 256MUse php_admin_value (admin) for values you don't want overridden by ini_set in user code. Use php_value if user code should be able to lower the limit but not raise it.
For per-application limits (multiple apps sharing one FPM master, each with its own pool):
; /etc/php/8.4/fpm/pool.d/wordpress.conf
[wordpress]
user = www-data
group = www-data
listen = /run/php/php8.4-wordpress.sock
php_admin_value[memory_limit] = 512M
; /etc/php/8.4/fpm/pool.d/laravel.conf
[laravel]
user = www-data
group = www-data
listen = /run/php/php8.4-laravel.sock
php_admin_value[memory_limit] = 256MReload FPM:
sudo systemctl reload php:php_version-fpmMethod 5: php -d flag (one-off CLI)
For Composer, PHPUnit, WP-CLI, artisan, drush — anything you run on the command line — pass -d memory_limit=... directly:
# Composer install with extra memory
php -d memory_limit=-1 /usr/local/bin/composer install
# PHPUnit on a large suite
php -d memory_limit=:value vendor/bin/phpunit
# WP-CLI
php -d memory_limit=:value $(which wp) plugin update --all
# Laravel artisan
php -d memory_limit=:value artisan migrate --seed
# Or invoke your own script with the limit raised
php -d memory_limit=:value :php_file-d overrides any setting in php.ini for that single invocation. No reload, no config edit, no side effects on other scripts. This is the right answer for "I need to run THIS command with more memory once".
For Composer specifically, the COMPOSER_MEMORY_LIMIT env var is an alias:
COMPOSER_MEMORY_LIMIT=-1 composer installMethod 6: WordPress wp-config.php
WordPress has its own memory abstraction layered on top of PHP. Two constants in wp-config.php:
define('WP_MEMORY_LIMIT', '256M'); // for normal page requests
define('WP_MAX_MEMORY_LIMIT', '512M'); // for admin and cron tasksWordPress applies these via ini_set on each request — they only work if ini_set is enabled and the underlying php.ini memory_limit isn't lower (PHP's limit is a ceiling; WordPress can only request UP TO that ceiling, not above it).
If you're hitting memory exhaustion specifically in admin (image-library imports, bulk-edit, plugin updates), raise WP_MAX_MEMORY_LIMIT. For front-end requests, WP_MEMORY_LIMIT is the one.
For specific WordPress memory pain points like bulk imports via wp_insert_post, see wp_insert_post Consuming Large Amounts of Memory — sometimes the right answer is fixing the script, not raising the limit.
Method 7: Docker / containers
For an official PHP container (or any image based on it), three ways depending on how the image is built:
(a) Mount a custom php.ini snippet:
# docker-compose.yml
services:
app:
image: php:8.4-fpm
volumes:
- ./docker/php-memory.ini:/usr/local/etc/php/conf.d/zz-memory.ini:ro; ./docker/php-memory.ini
memory_limit = 512MThe zz- prefix ensures the snippet loads last (and wins, since conf.d files load alphabetically).
(b) Use the PHP_INI_DIR and env-driven config in newer official images:
services:
app:
image: php:8.4-fpm
environment:
PHP_MEMORY_LIMIT: 512MRequires the image to honor the env var — most do via a startup shim, but check the image's docs.
(c) Override in the FPM pool:
volumes:
- ./docker/www.conf:/usr/local/etc/php-fpm.d/www.conf:roSame php_admin_value[memory_limit] = 512M line as Method 4.
For Docker Compose, the host's docker daemon also has a per-container memory cap — if you set PHP to 1G but the container is capped at 256M, the OOM-killer takes the whole container down. Pair PHP memory_limit with mem_limit in compose if you're being precise.
Common out-of-memory patterns
| Symptom | Fix |
|---|---|
composer install / composer update OOM | COMPOSER_MEMORY_LIMIT=-1 composer install (or php -d memory_limit=-1) |
phpunit OOM on large suites | php -d memory_limit=1G vendor/bin/phpunit, plus consider --testdox and process isolation |
wp_insert_post OOM during bulk import | Batch in chunks of 100-500, call wp_cache_flush() and gc_collect_cycles() between batches. See wp_insert_post memory deep-dive |
artisan migrate --seed OOM with large seed | php -d memory_limit=512M artisan ..., or chunk seeders with Model::query()->chunkById(1000, ...) |
| Image processing (GD/Imagick) OOM | Calculate (width × height × 4 × 2) bytes minimum; raise limit accordingly OR switch to streaming with imagick's readImageStream |
| Excel/CSV import OOM | Use streaming readers (PhpSpreadsheet's ReadFilter, league/csv's iterator interface) instead of loading the whole file |
| WordPress admin "white screen of death" | Set WP_MAX_MEMORY_LIMIT to 512M in wp-config.php — admin uses the max not the regular limit |
The first instinct should be "what is the script doing that needs more memory" — sometimes the real fix is the script, not the limit. Raising memory_limit is a band-aid; fixing the algorithm is the cure.
Verify the change took effect
After any change, confirm the runtime sees it:
# CLI — what php on the command line sees
php -i | grep memory_limit
# Output:
# memory_limit => :value => :valueThe first value is the runtime current; the second is the "master" value (from php.ini). If they differ, something has called ini_set after startup.
For the web SAPI, drop a one-line script in your document root:
<?php echo ini_get('memory_limit');Load it via the browser. The value you see is what the web SAPI is using for THIS request. Delete the file after — it's a small information leak.
Troubleshooting: why your change didn't apply
1. Edited the wrong php.ini. Run php --ini from CLI and phpinfo() from the web server. They typically use different files. Edit the right one.
2. PHP-FPM not reloaded. FPM caches the config at startup. After editing the pool file or php.ini, sudo systemctl reload php8.4-fpm. Apache mod_php similarly needs sudo systemctl reload apache2.
3. OPcache holding the old value. OPcache caches compiled PHP bytecode and the directive values are baked in. After a php.ini change, the OPcache might still serve old values for already-cached scripts until they're invalidated. Run opcache_reset() from a script you load, or restart the SAPI.
4. .htaccess silently ignored. PHP-FPM doesn't read .htaccess. If you're on Nginx, or on Apache with FPM proxying, the php_value line in .htaccess is a no-op. Switch to Method 4.
5. ini_set blocked by host. Some shared hosts add memory_limit to a "locked settings" list. ini_get('memory_limit') after ini_set will show the unchanged value. Contact support or switch hosts.
6. The script ran out of memory BEFORE ini_set. If you load a huge file with file_get_contents on line 1 and call ini_set on line 2, line 1 already triggered the fatal. Move the ini_set to the very top, before any allocation.
7. Container memory cap below PHP limit. Docker/Kubernetes will OOM-kill the container before PHP sees the limit. Match the container's mem_limit to PHP's memory_limit (slightly above).
8. php_admin_value in FPM overrides everything. ini_set in user code can't override php_admin_value — that's the point. If you need user code to be able to raise the limit, use php_value in the pool config instead.
What to do next
For specific PHP/WordPress memory situations:
- wp_insert_post Consuming Large Amounts of Memory — when the right fix is the import script, not the memory_limit.
- How to Use ElasticPress with WP_Query — moving search load off MySQL to reduce per-request memory.
- How to Remove Empty Values from a PHP Array — micro-optimisation reference for the kind of cleanup that often follows large-array memory issues.
For WordPress administration:
- How to Change a WordPress Password — adjacent admin-recovery reference, especially relevant if you got locked out while debugging a white-screen-of-death.
FAQ
See also
- wp_insert_post Consuming Large Amounts of Memory: a WordPress-specific memory pattern where raising the PHP limit treats the symptom; this article finds the leak in
wp_insert_post - WordPress Fatal Error: Call to Undefined Function get_option: the other "WordPress just exploded" error class, where the fix is initialization order rather than memory
- WordPress Sending HTML-Formatted Emails Using wp_mail(): mail bodies render via
wp_mail, which is one of the calls that spikes memory if the body is large; relevant when triaging which call is the offender - How to Remove WordPress Malware: The Practitioner's Playbook: if
wp_insert_postor other PHP processes are spiking memory unexpectedly, sometimes the cause is a malicious backdoor inside the same code path, not a legitimate plugin overusing memory





