Last updated: July 2026 — paths shown for PHP 8.3 on Ubuntu 24.04
Uploads failing at exactly 2 MB is PHP’s default limit, not your application. Three settings govern it, and they must agree.
1. Find the php.ini actually in use
Ubuntu keeps separate configs per PHP version and per runtime:
/etc/php/8.3/apache2/php.ini ← Apache with mod_php
/etc/php/8.3/fpm/php.ini ← nginx or Apache with PHP-FPM
/etc/php/8.3/cli/php.ini ← command line only
Don’t guess — ask PHP itself. Create a page with <?php phpinfo(); and check “Loaded Configuration File”, or for the web runtime on FPM: php-fpm8.3 -i | grep 'Loaded Config'. Editing the CLI ini and wondering why nothing changed is the #1 time-waster here.
2. Set the three values
upload_max_filesize = 64M
post_max_size = 72M
memory_limit = 256M
The relationship matters: a POST request contains the file plus form fields, so post_max_size must exceed upload_max_filesize (a little headroom is enough), and memory_limit should comfortably exceed both. If post_max_size is the smaller value, PHP silently delivers an empty $_POST and $_FILES — no error, just missing data, which is maddening to debug.
Also worth raising for slow connections:
max_execution_time = 120
max_input_time = 120
3. Restart the right service
# Apache with mod_php
sudo systemctl restart apache2
# PHP-FPM (nginx, or Apache+FPM)
sudo systemctl restart php8.3-fpm
4. Verify
php -r "echo ini_get('upload_max_filesize');" # checks CLI ini only!
For the web value, reload your phpinfo() page — both upload_max_filesize and post_max_size should show the new numbers in the Local Value column.
Still capped? The web server has its own limit
On nginx, uploads bigger than 1 MB die with 413 Request Entity Too Large before PHP ever sees them:
# inside http {} or server {}
client_max_body_size 64M;
then sudo systemctl reload nginx. On shared hosting without php.ini access, the same PHP settings usually work from .user.ini (FPM) or php_value lines in .htaccess (mod_php).
Finally, remember your application may validate on top of all this — Laravel’s max: rule counts in kilobytes and rejects independently of php.ini; the full upload flow is in Laravel file uploads done right.
