How to bypass WordPress memory_limit hardcoded by server php.ini limits

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.

See also  WordPress wp_cron.php causing high CPU usage: Proper CLI systemd timer setup

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.

See also  WooCommerce tax calculation mismatch: Inclusive vs exclusive tax on coupon discounts

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 by ini_set, .user.ini, .htaccess, or wp-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_LIMIT below the server value does nothing, because WordPress only raises the limit. WP_MAX_MEMORY_LIMIT applies 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.ini cache adds up to 300 seconds of delay.
  • Wrong error attribution: Allowed memory size of 134217728 bytes exhausted names 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 and Out of memory: Killed process in dmesg, is the kernel or cgroup OOM killer. No memory_limit setting prevents it.
  • Container and cgroup limits: A memory_limit of 1G inside a Docker container capped at 512M (--memory=512m) is never reached; the container is killed first. Check with docker 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. Set memory_limit to the realistic peak and lower pm.max_children to 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.
See also  Fixing WordPress media upload error: "HTTP error" without debug logs in wp-config

Leave a Comment