Large uploads can fail before the application code ever sees the request, which blocks media libraries, backup restores, theme or plugin installers, and bulk imports that depend on normal multipart uploads. Raising the effective PHP upload size limit lets legitimate requests reach the application instead of being discarded at the runtime boundary.
The upload ceiling is a chain rather than one setting. upload_max_filesize limits each uploaded file, post_max_size limits the full request body, and larger uploads can still need extra memory_limit headroom while the application parses archives, images, or other heavy payloads. When a request exceeds post_max_size, the body can reach the script without the expected $_POST or $_FILES data.
Verify the same runtime that serves the site, not only the CLI binary in PATH. PHP-FPM pool directives, per-directory .user.ini files on CGI/FastCGI, Apache overrides, or smaller request-body limits in Apache, Nginx, a load balancer, or another reverse proxy can still override the base php.ini file.
Related: How to increase PHP memory limit
Related: How to limit request body size in Apache
Related: How to limit request sizes in Nginx
Steps to increase PHP upload size limit:
- Create a temporary diagnostic script under the same site path that handles uploads.
$ sudo tee /var/www/app.example.test/public/upload-check.php >/dev/null <<'PHP' <?php header('Content-Type: text/plain'); printf("SAPI=%s\n", PHP_SAPI); printf("Loaded php.ini=%s\n", php_ini_loaded_file() ?: 'none'); printf("upload_max_filesize=%s\n", ini_get('upload_max_filesize')); printf("post_max_size=%s\n", ini_get('post_max_size')); printf("memory_limit=%s\n", ini_get('memory_limit')); printf("max_input_time=%s\n", ini_get('max_input_time')); printf("max_file_uploads=%s\n", ini_get('max_file_uploads')); if ($_SERVER['REQUEST_METHOD'] === 'POST') { $file = $_FILES['upload'] ?? null; if (!$file) { echo "upload_status=missing\n"; } elseif ($file['error'] !== UPLOAD_ERR_OK) { printf("upload_error=%d\n", $file['error']); } else { printf("upload_error=0\n"); printf("upload_name=%s\n", $file['name']); printf("upload_size=%d\n", $file['size']); } } PHPKeep the probe under the same virtual host, document root, or PHP-FPM pool that receives the real uploads so the result reflects the request-side configuration.
Remove the diagnostic file after testing because it exposes runtime details to anyone who can reach the URL.
- Request the diagnostic script before changing the limit.
$ curl -sS https://app.example.test/upload-check.php SAPI=fpm-fcgi Loaded php.ini=/etc/php/8.5/fpm/php.ini upload_max_filesize=2M post_max_size=8M memory_limit=128M max_input_time=60 max_file_uploads=20
If the response shows apache2handler, inspect Apache override points before changing the global php.ini. If it shows fpm-fcgi, inspect the matching PHP-FPM pool and any nearer .user.ini files before assuming the main file is the active layer.
Related: How to find PHP configuration files
- Search PHP-FPM pool files for an active upload-size override when the diagnostic request reports fpm-fcgi.
$ sudo grep -R "upload_max_filesize" /etc/php/8.5/fpm/pool.d
No output means the pool files are not currently overriding the per-file upload limit. If a pool file sets upload_max_filesize, post_max_size, memory_limit, max_input_time, or max_file_uploads, change that pool file instead because it wins for requests handled by that pool.
On many RHEL-family systems, search /etc/php-fpm.d instead.
- Back up the file that currently controls the effective upload limit.
$ sudo cp /etc/php/8.5/fpm/php.ini /etc/php/8.5/fpm/php.ini.bak-$(date +%Y%m%d%H%M%S)
Back up the discovered pool file, Apache override file, or existing .user.ini instead when an earlier check shows that layer is setting the live value.
Keep the backup until a larger upload is confirmed through the same site path.
- Open the controlling configuration file in a text editor.
$ sudoedit /etc/php/8.5/fpm/php.ini
Open the discovered pool file, Apache override file, or .user.ini instead when that layer owns the active value.
Related: How to find PHP configuration files
- Set the per-file and full-request limits high enough for the largest legitimate upload.
; php.ini or .user.ini upload_max_filesize = 128M post_max_size = 160M memory_limit = 256M
post_max_size must stay larger than upload_max_filesize so the full multipart request can reach PHP. Keep memory_limit above the amount of memory the application needs while parsing or processing uploaded data.
In a PHP-FPM pool file, use the existing pool syntax, such as php_value[upload_max_filesize] = 128M and php_value[post_max_size] = 160M. Use php_admin_value[] only when the pool should prevent lower layers from changing the value.
- Increase max_input_time only when large or slow uploads time out while PHP is still receiving the request body.
max_input_time = 300
max_input_time covers request parsing time, including file uploads. max_execution_time applies after script execution begins.
- Increase max_file_uploads only when one submission legitimately carries many files.
max_file_uploads = 50
PHP counts populated upload fields toward this limit, so blank upload inputs do not consume the quota.
- Test the PHP-FPM configuration before reloading the runtime.
$ sudo php-fpm8.5 -t [06-Jun-2026 01:31:26] NOTICE: configuration file /etc/php/8.5/fpm/php-fpm.conf test is successful
Use the binary that matches the runtime serving the site, such as php-fpm or php-fpm8.4. Skip this syntax test when the only change lives in .user.ini or an Apache override.
Do not reload the runtime until the configuration test succeeds.
- Reload the runtime that serves the application so new workers read the updated directives.
$ sudo systemctl reload php8.5-fpm
Reload Apache instead when PHP runs as an Apache module, and use the unversioned php-fpm unit on hosts that package it that way. A .user.ini change is picked up after the user_ini.cache_ttl interval instead of a service reload.
- Request the diagnostic script again and confirm the higher live values from the web-facing runtime.
$ curl -sS https://app.example.test/upload-check.php SAPI=fpm-fcgi Loaded php.ini=/etc/php/8.5/fpm/php.ini upload_max_filesize=128M post_max_size=160M memory_limit=256M max_input_time=300 max_file_uploads=50
If smaller values still appear, check for a later PHP-FPM pool override, a nearer .user.ini file, an Apache php_value or php_admin_value override, or a smaller request-body limit in Apache, Nginx, a load balancer, or another reverse proxy.
Related: How to find PHP configuration files
- Create a temporary file that is larger than the old limit but smaller than the new limit.
$ truncate -s 32M /tmp/upload-smoke.bin
Use a test size that proves the new limit without stressing the application, disk, or network path.
- Post the temporary file through the diagnostic script and confirm upload_error=0.
$ curl -sS -F upload=@/tmp/upload-smoke.bin https://app.example.test/upload-check.php SAPI=fpm-fcgi Loaded php.ini=/etc/php/8.5/fpm/php.ini upload_max_filesize=128M post_max_size=160M memory_limit=256M max_input_time=300 max_file_uploads=50 upload_error=0 upload_name=upload-smoke.bin upload_size=33554432
If the response is an HTTP 413 before PHP output appears, raise the request-body limit in Nginx, Apache, a load balancer, or another reverse proxy. If upload_status=missing or upload_error=1 appears, recheck post_max_size and upload_max_filesize in the active PHP layer.
- Remove the temporary upload file.
$ rm /tmp/upload-smoke.bin
- Remove the temporary diagnostic script.
$ sudo rm /var/www/app.example.test/public/upload-check.php
Leaving the file reachable keeps the active SAPI, loaded configuration path, and runtime limits exposed to anyone who can request the URL.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.