The file won't upload: upload_max_filesize, post_max_size and the limit that wins
Four limits in a row block the upload: two from PHP, one from the web server, one from the application. How to work out which one is stopping you, and how to change them on a VPS, cPanel and Plesk.
UptimeMag editorial team · 10 October 2026 · 6 min read

First thing to do: look at the exact message
If the site appears stuck and the client keeps pressing "upload" with no result, don't waste time reading the whole guide: look at the error message. It already answers half the question.
- A blank page or 413 Request Entity Too Large: that's the web server (Nginx), not PHP.
- A PHP message saying "The uploaded file exceeds the upload_max_filesize directive": that's
upload_max_filesize. - The form resets,
$_POSTand$_FILEScome back empty, no visible error: almost alwayspost_max_sizehas been exceeded. - An application error (WordPress, Moodle, a CMS) showing a figure different from what you set in PHP: there's a fourth limit, the one imposed by the application itself.
The four limits, in order of how often they actually block an upload
1. upload_max_filesize (PHP)
This limits the size of the single uploaded file. The PHP manual states that upload_max_filesize int: The maximum size of an uploaded file. The default value is "2M".
How to tell if this is the cause: the PHP message names it explicitly, or the upload error code shows UPLOAD_ERR_INI_SIZE.
2. post_max_size (PHP)
This limits the total size of the POST request, not just the file: text fields, multipart headers and the file all together. The PHP manual is unambiguous: To upload large files, this value must be larger than upload_max_filesize. If the whole request exceeds this value, If the size of post data is greater than post_max_size, the $_POST and $_FILES superglobals are empty.
This is the sneaky case: no visible error, the form just seems to "do nothing". If you see an empty $_FILES with no error message at all, check post_max_size first.
3. client_max_body_size (Nginx)
This is the web server's limit on the size of the entire request body, before PHP even sees it. From the official nginx.org documentation: this is the maximum size of a client request body. If this size is exceeded, Nginx returns a 413 Request entity too large HTTP error. The default is 1m.
If you get a 413 and the page isn't even your CMS's own error page but a generic Nginx error page, this is the culprit, not PHP.
4. The application's own limit
Many applications (WordPress, Moodle, management software, custom upload panels) add their own ceiling, independent of PHP and the web server, often configurable from a panel or in code. If, after raising all three limits above, the error stays exactly the same with the same figure, it's the application imposing its own limit.
How to change them, system by system
On a VPS with Ubuntu 24.04, Nginx and PHP-FPM
For PHP-FPM, edit the ini file of the PHP version in use (the path varies depending on the version installed, typically under /etc/php/8.x/fpm/php.ini):
upload_max_filesize = 64M
post_max_size = 72M
Restart PHP-FPM with the command (replace 8.3 with your version):
sudo systemctl restart php8.3-fpm
For Nginx, in the server or http block of the site's configuration file:
client_max_body_size 72M;
Check the syntax and reload:
sudo nginx -t
sudo systemctl reload nginx
A note on syntax: the value of client_max_body_size is written without a space between the number and the unit, and with a lowercase m in the official example (1m), whereas PHP uses an uppercase M (64M): these are two different parsers, so it's not a mistake if you see them written differently.
On cPanel
On cPanel, the PHP values are changed from MultiPHP INI Editor, which writes directly to the ini file of the PHP version assigned to the domain: this is where you set both upload_max_filesize and post_max_size. cPanel usually runs Apache with mod_php or PHP-FPM behind Apache, so there's generally no separate Nginx client_max_body_size to manage, unless the provider has added Nginx as a reverse proxy in front of Apache: in that case the Nginx limit still exists and needs to be found in the proxy configuration, not in the user panel.
On Plesk
On Plesk, the two PHP values are changed from Domains > domainname > PHP Settings (or "Dashboard > PHP" in more recent versions), where both fields appear: for a specific domain: Log in to Plesk, Go to Domains > example.com > PHP Settings, and edit upload_max_filesize and post_max_size. The default value in Plesk for upload_max_filesize is 2 MB.
If the domain is served by Nginx (some Plesk setups use Nginx as a reverse proxy in front of Apache, others use it directly as the server for PHP-FPM), there's an equivalent limit here too, to client_max_body_size, managed by the panel as "Maximum allowed HTTP request body size" in the domain's or service plan's Nginx settings: Go to Service Plans, Set the Maximum allowed HTTP request body size (also known as client_max_body_size) to the same value that you used for post_max_size and upload_max_filesize.
The classic mistake: changing just one of them
The most common case seen in support: upload_max_filesize is raised to 500M, the file still won't upload, and the sysadmin swears they've "fixed the problem". They haven't: they've just shifted the bottleneck onto one of the other three limits. A PHP community thread sums it up well: $_FILES will be empty if a user attempts to upload a file greater than post_max_size in your php.ini, post_max_size should be >= upload_max_filesize in your php.ini.
The practical rule, valid everywhere: the four limits need to be raised together, and in this order of magnitude — client_max_body_size (Nginx) ≥ post_max_size (PHP) > upload_max_filesize (PHP), with some margin for multipart overhead, plus any application limit raised separately.
A practical case: uploading a 500 MB video or backup
For a 500 MB file you need, as a bare minimum:
upload_max_filesize = 512M
post_max_size = 550M
client_max_body_size 550M;
The margin between upload_max_filesize and post_max_size is there to cover the form fields and multipart headers that travel alongside the file. On Plesk, for uploads of this size, the panel directly suggests values in gigabytes: file_uploads = on, upload_max_filesize = 3500M, post_max_size = 3500M. Instead of "3500M" you can use gigabytes, for example "4G".
Also remember PHP's memory_limit: the manual recommends that memory_limit should be larger than post_max_size, otherwise PHP runs out of memory before it can even validate the file.
How to verify it's fixed
- Check the values actually in effect, not just what's written in the file: from the command line,
php -i | grep -E "upload_max_filesize|post_max_size|memory_limit"(on Ubuntu/PHP-FPM) reads the configuration genuinely loaded by the running PHP process, not a file that might not even be read. - For Nginx, check which directive is actually in use with
sudo nginx -T | grep client_max_body_size: if more than one line appears, the one in the more specific block wins (location beats server, server beats http). - Run a real test with a file at the limit size +10%, not just a small file: a 2 MB file will pass even with factory defaults, and proves nothing about the limit you actually care about.
- If the file still gets stuck after raising all three levels (PHP, web server, application), the problem may lie further upstream, on the provider's side: on many shared hosting setups, the provider imposes a ceiling that can't be changed from the client panel. In that case, open a ticket stating the exact file size, the full error message, and the current values of
upload_max_filesize,post_max_sizeandclient_max_body_sizeyou've already tried: without this information, support can't tell a platform limit apart from a configuration error.
Written with the help of artificial intelligence and checked by the editors (EU AI Act, art. 50).