Root Cause Diagnosis
WordPress WP_MEMORY_LIMIT and WP_MAX_MEMORY_LIMIT only request a higher limit through ini_set('memory_limit', ...) at runtime, and that call silently fails when the server has locked the directive. The lock comes from php_admin_value[memory_limit] in a PHP-FPM pool file, php_admin_value in an Apache or OpenLiteSpeed vhost, ini_set listed in disable_functions, or Suhosin’s suhosin.memory_limit. WordPress also never lowers a limit, so any constant below the server value is a no-op. The limit therefore has to be changed at the layer that sets it.
Quick Fix
Add the constants to wp-config.php, above the line /* That's all, stop editing! */:
define( 'WP_MEMORY_LIMIT', '256M' ); // front end and general requests
define( 'WP_MAX_MEMORY_LIMIT', '512M' ); // admin, imports, updates, image processing
Verify the effective value, not the constant:
wp eval 'var_dump( ini_get("memory_limit"), WP_MEMORY_LIMIT, WP_MAX_MEMORY_LIMIT );'
If ini_get("memory_limit") still returns the old value, the limit is locked server-side. Continue with the steps below.
Step-by-Step Resolution
1. Identify which layer sets the limit.
The CLI and the web SAPI read different ini files, so php -i can report a value the web server never uses. Check both:
# CLI (not authoritative for web requests)
php -i | grep -E "Loaded Configuration File|Scan this dir|^memory_limit"
# Search every layer for the directive
grep -rniE "memory_limit" /etc/php/ /etc/php-fpm.d/ /usr/local/etc/php/ \
/etc/apache2/ /etc/httpd/ /usr/local/lsws/conf/ 2>/dev/null
For the web value, drop a temporary file in the web root, then delete it immediately:
<?php // **/var/www/html/pi.php**
phpinfo();
In the output, check Loaded Configuration File, Scan this dir for additional .ini files, and the memory_limit row. If Local Value equals Master Value and both ignore your overrides, the directive is locked (php_admin_value) or the wrong file is being edited.
2. Check whether ini_set is disabled.
wp eval 'echo ini_get("disable_functions");'
If ini_set appears, WP_MEMORY_LIMIT can never work. Remove it from disable_functions in the active php.ini or raise the limit at a layer in steps 3-6.
3. Override in php.ini (requires root or VPS access).
Do not edit the packaged php.ini. Use a late-loading drop-in so package upgrades do not overwrite it.
Debian/Ubuntu: /etc/php/8.3/fpm/conf.d/99-memory.ini RHEL/Alma/Rocky: /etc/php.d/99-memory.ini Official Docker image: /usr/local/etc/php/conf.d/99-memory.ini
memory_limit = 256M
Apply the change:
sudo systemctl reload php8.3-fpm # or php-fpm, depending on distro
sudo apachectl graceful # only if using mod_php
4. Fix a PHP-FPM pool lock.
Edit the pool file for the site’s pool: /etc/php/8.3/fpm/pool.d/www.conf (Debian), /etc/php-fpm.d/www.conf (RHEL), or a per-site pool file.
; Locked: ini_set(), .user.ini and .htaccess cannot override this
php_admin_value[memory_limit] = 256M
; Unlocked default: lets WP_MEMORY_LIMIT and WP_MAX_MEMORY_LIMIT raise it at runtime
php_value[memory_limit] = 256M
Change the value, or switch php_admin_value to php_value to restore runtime overrides, then run sudo systemctl reload php8.3-fpm.
5. Use .user.ini on FPM/FastCGI hosts without root.
Create /path/to/wordpress/.user.ini:
memory_limit = 256M
PHP caches .user.ini for user_ini.cache_ttl seconds (default 300), so changes can take up to 5 minutes. This file is ignored when the directive is locked with php_admin_value, and it is not read under mod_php.
6. Use .htaccess on Apache mod_php or LiteSpeed.
In /path/to/wordpress/.htaccess:
<IfModule mod_php.c>
php_value memory_limit 256M
</IfModule>
<IfModule LiteSpeed>
php_value memory_limit 256M
</IfModule>
On PHP 7.x, use mod_php7.c. Nginx ignores .htaccess entirely. On Apache with PHP-FPM, php_value in .htaccess triggers a 500 error or is ignored; use step 4 or 5 instead.
7. Use the control-panel override mechanism.
Panels regenerate pool and vhost files, so manual edits get overwritten. Use the panel’s own setting:
- cPanel/WHM: WHM > MultiPHP INI Editor (server-wide), or cPanel > Software > MultiPHP INI Editor (per domain).
- Plesk: Domains > example.com > PHP Settings > memory_limit.
- aaPanel: App Store > PHP-8.x > Setting > Performance Tuning (or Configuration file to edit php.ini directly), then restart PHP.
- CyberPanel (OpenLiteSpeed): Websites > List Websites > Manage > vHost Conf, or PHP > Edit PHP Configs for server-wide values. Per-vhost override:
phpIniOverride {
php_admin_value memory_limit "512M"
}
Restart OpenLiteSpeed after saving: sudo systemctl restart lsws.
8. Confirm the change took effect and sizes correctly.
curl -s https://example.com/pi.php | grep -iE "memory_limit"
Then delete pi.php. Also check Tools > Site Health > Info > Server in wp-admin, which shows both the PHP memory limit and the WordPress memory limit.
Why This Fails for Some Users
- Edited the wrong php.ini: The CLI, FPM, Apache, and each installed PHP version use separate files. Confirm Loaded Configuration File in web-served
phpinfo(), not from SSH. - Locked by
php_admin_value: The directive cannot be changed byini_set,.user.ini,.htaccess, orwp-config.php. Only the pool or vhost file can change it, which requires root or a support request on shared hosting. - Shared-host hard caps: Many hosts enforce a per-account limit (for example 128M or 256M) outside your control, and plan tiers often gate it. Only the host can raise it.
- Value mismatch across constants:
WP_MEMORY_LIMITbelow the server value does nothing, because WordPress only raises the limit.WP_MAX_MEMORY_LIMITapplies only in admin contexts such as updates, imports, and image resizing, not on front-end requests. - PHP not reloaded: FPM and OpenLiteSpeed keep workers running with the old configuration until a reload or restart. The
.user.inicache adds up to 300 seconds of delay. - Wrong error attribution:
Allowed memory size of 134217728 bytes exhaustednames the limit actually hit (134217728 = 128M, 268435456 = 256M, 536870912 = 512M). If the byte value does not match your configured value, a different layer is applying the limit. A 502, or a worker killed with exit code 137 andOut of memory: Killed processindmesg, is the kernel or cgroup OOM killer. Nomemory_limitsetting prevents it. - Container and cgroup limits: A
memory_limitof 1G inside a Docker container capped at 512M (--memory=512m) is never reached; the container is killed first. Check withdocker inspect --format '{{.HostConfig.Memory}}' <container>. - RAM capacity math: Worst-case consumption is
pm.max_children × memory_limit. A pool of 20 workers at 512M can demand 10 GB. Setmemory_limitto the realistic peak and lowerpm.max_childrento fit physical RAM. - Raising the limit hides leaks: If usage climbs with each request or plugin action, identify the cause with Query Monitor or
define( 'SAVEQUERIES', true );plus a profiler, instead of increasing the ceiling repeatedly.