PHP ships with an upload limit of 2MB and a maximum script execution time of 30 seconds by default, values chosen decades ago and never really revisited since. Neither fits WordPress well. A single unoptimised product photo from a modern phone camera can exceed 2MB on its own, and importing a plugin's demo content or running a theme's built-in import tool frequently takes longer than 30 seconds to finish, especially with a database of any real size. Both show up as unhelpful, generic errors that give no indication the fix is a PHP setting rather than a WordPress problem.
This guide raises both settings correctly at the PHP-FPM level, the layer that actually enforces them regardless of what WordPress itself is configured to allow. It assumes PHP-FPM is already running behind Nginx, for example from the [WordPress deployment guide](/guides/deploy-wordpress-nginx-php-fpm).
PHP-FPM reads its settings from a php.ini file specific to the FPM SAPI, separate from the CLI php.ini used when running PHP from the command line; editing the wrong one is a common reason a change appears to have no effect. Confirm the correct path:
php-fpm8.3 -i | grep 'Loaded Configuration File'
Output:
Loaded Configuration File => /etc/php/8.3/fpm/php.ini
Replace 8.3 with your installed PHP version throughout this guide if different; check with php -v if unsure. This is the file to edit, not /etc/php/8.3/cli/php.ini, which only affects PHP run directly from a terminal.
Open the FPM php.ini file confirmed in step 1:
sudo nano /etc/php/8.3/fpm/php.ini
Find and update these three directives, which work together rather than independently:
upload_max_filesize = 64M
post_max_size = 72M
memory_limit = 256M
upload_max_filesize caps the size of a single uploaded file. post_max_size caps the total size of the entire POST request, which includes the file plus form data and any other files in a multi-file upload, and must always be set higher than upload_max_filesize; if it is equal or lower, uploads fail silently with no clear error pointing at the actual cause. memory_limit needs enough headroom to process the upload in memory during handling, and 256M covers a 64M upload comfortably; setting memory_limit lower than the upload size causes a different, equally unhelpful failure.
64M is a reasonable ceiling for most WordPress sites, well above what a photo or a typical PDF needs, without leaving the door open to arbitrarily large uploads eating disk space or memory. Raise it further only if you have a specific, known reason, such as uploading video files directly through the media library.
In the same file, find and update max_execution_time:
max_execution_time = 120
This raises the ceiling from 30 seconds to 120, enough headroom for a plugin import, a theme demo content install, or a large search-replace operation to finish without PHP killing the process mid-task. Do not set this to 0, which means unlimited; a runaway script with no time limit at all can hold a PHP-FPM worker indefinitely, and on a VPS with a fixed, limited pool of workers, that is how a single stuck request starts queuing up every other request behind it.
PHP's settings only control what PHP itself will accept; Nginx sitting in front of it enforces its own separate limit and rejects anything over it before PHP ever sees the request. Open your site's server block:
sudo nano /etc/nginx/sites-available/example.com
Add or update client_max_body_size inside the server block, matching or slightly exceeding the post_max_size set in step 2:
client_max_body_size 72M;
Without this, a large upload can pass PHP's own limits and still fail with a generic Nginx 413 error, which looks identical to a PHP-level failure from the browser but requires a completely different fix. Test and reload Nginx:
sudo nginx -t
sudo systemctl reload nginx
php.ini changes do not take effect until PHP-FPM restarts, since the values are read once at startup rather than on every request. Restart the service:
sudo systemctl restart php8.3-fpm
Confirm the new values actually took effect by checking WordPress's own view of them, which reads directly from PHP rather than relying on a cached value. Log into wp-admin and go to Media, Add New; WordPress displays the current maximum upload size on that screen, sourced live from upload_max_filesize and post_max_size. It should now show the new limit rather than the original 2MB default.
WordPress can now accept uploads up to 64MB and run scripts for up to two minutes before timing out, matched correctly across PHP-FPM and Nginx so neither layer silently overrides the other. From here, if imports or uploads still feel slow rather than outright failing, that points toward a different problem, PHP-FPM pool sizing or OPcache configuration, covered in the [guide to tuning PHP-FPM and OPcache for WordPress](/guides/tune-php-fpm-opcache-wordpress-vps).
Move a live WordPress site from shared hosting to a VPS: database export with my...
How to set up SSH key authentication on Ubuntu and disable password logins to se...
Install WordPress on a Linux VPS with Nginx, PHP-FPM, and MariaDB. Complete step...