Skip to main content
Being Idea Innovations
How to Increase the Maximum File Upload Size in PHP (and Why Your Change Isn't Working)
Back to Blog

How to Increase the Maximum File Upload Size in PHP (and Why Your Change Isn't Working)

4 May 20186 min readPHP
Share:

"Increase the upload limit" sounds like a one-line change and frequently takes an afternoon, because the setting lives in a different place depending on how PHP is running, and several directives have to agree before anything works.

This guide covers which method applies to your setup, and why the advice you have probably already tried did nothing.

First: why the popular fix does not work

This snippet appears in countless articles, including the earlier version of this one:

// Does nothing. At all.
@ini_set( 'upload_max_size' , '64M' );
@ini_set( 'post_max_size', '64M' );

Two separate bugs:

  • There is no directive called upload_max_size. It is upload_max_filesize. The line sets a nonexistent setting and returns silently.
  • Both directives are PHP_INI_PERDIR. That means they can only be set in php.ini, .htaccess, or the server config — never at runtime. By the time your PHP script executes, the upload has already been received or rejected. Changing the limit mid-request is too late by definition.

The @ suppresses the warning that would have told you. Remove error suppression and you would have seen the problem immediately.

Find out how PHP is running

This determines which method works. Create a file and load it in a browser:

<?php phpinfo();

Look at Server API near the top:

Server APIUse.htaccess works?
Apache 2.0 Handlerphp.ini or .htaccessYes
FPM/FastCGIphp.ini or pool configNo — causes a 500 error
CGI/FastCGIphp.ini in the directoryNo
LiteSpeedphp.ini or .htaccessUsually

Also note Loaded Configuration File — that is the php.ini actually in use. Editing a different one, which is easy to do when several exist, is the most common reason a change appears to have no effect. Delete the file when you are finished; phpinfo() exposes a great deal about your server.

From the command line:

php -i | grep -E "Loaded Configuration|upload_max_filesize|post_max_size"

Note that CLI often uses a different php.ini from the web server, so the command line reporting 64M tells you nothing about what your site is doing.

The directives that must all agree

Raising only upload_max_filesize is the second most common mistake. Five settings interact:

; The largest single uploaded file.
upload_max_filesize = 64M

; The largest total POST body. MUST exceed upload_max_filesize —
; it has to hold the file plus every other form field plus encoding overhead.
post_max_size = 68M

; Memory available to the script.
memory_limit = 128M

; Seconds the script may run. Large uploads on slow connections need headroom.
max_execution_time = 300

; Seconds allowed to PARSE input, including receiving the upload.
; This is the one people forget — the upload can time out here
; even with a generous max_execution_time.
max_input_time = 300

; Only if you accept several files at once.
max_file_uploads = 20

The ordering rule: memory_limitpost_max_size > upload_max_filesize.

If post_max_size is smaller than upload_max_filesize, PHP discards the request body and $_POST and $_FILES arrive completely empty — with no error. A form that silently submits nothing is almost always this.

Method 1 — php.ini (works everywhere)

Edit the file named in Loaded Configuration File, set the values above, and restart:

# mod_php
sudo systemctl restart apache2

# PHP-FPM — restart the FPM service, not just the web server
sudo systemctl restart php8.3-fpm

Forgetting to restart FPM is a classic. The config is read once at startup, so your edit sits there having no effect until the process reloads.

Method 2 — .htaccess (mod_php and LiteSpeed only)

php_value upload_max_filesize 64M
php_value post_max_size 68M
php_value max_execution_time 300
php_value max_input_time 300

Under PHP-FPM this produces a 500 Internal Server Error — Apache does not recognise php_value when PHP is not loaded as a module. If your site breaks the moment you save this file, that is your answer: you are on FPM, use php.ini instead.

Wrap it defensively if you are unsure:

<IfModule mod_php.c>
  php_value upload_max_filesize 64M
  php_value post_max_size 68M
</IfModule>

Method 3 — a php.ini in the directory (CGI/FastCGI)

On shared hosting running PHP as CGI, a php.ini placed in your web root applies to that directory:

upload_max_filesize = 64M
post_max_size = 68M
memory_limit = 128M

Two caveats. It usually does not cascade into subdirectories — some hosts need a copy in each, or a suPHP_ConfigPath directive in .htaccess. And it does nothing at all under mod_php.

Method 4 — PHP-FPM pool config

The correct place on a modern VPS. Edit your pool file, typically /etc/php/8.3/fpm/pool.d/www.conf:

php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 68M
php_admin_value[memory_limit] = 128M

php_admin_value cannot be overridden by ini_set() at runtime; plain php_value can. Use php_admin_value for limits you want enforced.

The nginx setting nobody mentions

If you run nginx, PHP is not your only limit. nginx rejects large bodies before PHP ever sees them, and the default is a mere 1 MB:

http {
    client_max_body_size 64M;
    client_body_timeout 300s;
}

The symptom is distinctive: 413 Request Entity Too Large, served by nginx, with nothing in your PHP logs. If you have raised every PHP directive and still cannot upload, this is almost certainly why.

sudo nginx -t && sudo systemctl reload nginx

Cloudflare imposes its own cap too — 100 MB on the free plan — and returns a 413 of its own regardless of your server settings.

Verify from PHP

<?php
printf(
    "upload_max_filesize: %s\npost_max_size: %s\nmemory_limit: %s\nmax_execution_time: %s\n",
    ini_get('upload_max_filesize'),
    ini_get('post_max_size'),
    ini_get('memory_limit'),
    ini_get('max_execution_time')
);

A helper that reports the real ceiling — the smaller of the two limits — is worth having, since that is what users actually experience:

function maxUploadBytes(): int
{
    $toBytes = static function (string $value): int {
        $value = trim($value);
        if ($value === '' || $value === '-1') return PHP_INT_MAX;

        $unit = strtolower($value[strlen($value) - 1]);
        $num  = (int) $value;

        return match ($unit) {
            'g' => $num * 1024 ** 3,
            'm' => $num * 1024 ** 2,
            'k' => $num * 1024,
            default => $num,
        };
    };

    return min(
        $toBytes(ini_get('upload_max_filesize')),
        $toBytes(ini_get('post_max_size'))
    );
}

Handle the failure properly

When an upload exceeds post_max_size, PHP empties $_POST and $_FILES entirely — so your usual "no file submitted" branch fires and gives the user a misleading message. Detect it explicitly:

if ($_SERVER['REQUEST_METHOD'] === 'POST'
    && empty($_POST)
    && empty($_FILES)
    && (int) ($_SERVER['CONTENT_LENGTH'] ?? 0) > 0) {

    $limit = ini_get('post_max_size');
    exit("Your upload was too large. The maximum is {$limit}.");
}

// And check the per-file error code.
match ($_FILES['doc']['error'] ?? UPLOAD_ERR_NO_FILE) {
    UPLOAD_ERR_OK        => handleUpload($_FILES['doc']),
    UPLOAD_ERR_INI_SIZE  => fail('File exceeds the server limit.'),
    UPLOAD_ERR_FORM_SIZE => fail('File exceeds the form limit.'),
    UPLOAD_ERR_PARTIAL   => fail('Upload was interrupted. Please retry.'),
    UPLOAD_ERR_NO_FILE   => fail('No file was selected.'),
    UPLOAD_ERR_NO_TMP_DIR,
    UPLOAD_ERR_CANT_WRITE => fail('Server storage error. Contact support.'),
    default => fail('Upload failed.'),
};

Tell the user the limit in the interface as well, so they find out before spending five minutes uploading.

Should you raise it?

A large post_max_size means any visitor can make your server buffer that much data per request — a cheap way to exhaust resources. For genuinely large files, consider chunked uploads (splitting client-side and reassembling) or presigned direct-to-storage uploads to S3 or similar, which bypass your server entirely.

Checklist when it still will not work

  1. Check Server API — are you using the right method?
  2. Check Loaded Configuration File — did you edit the right php.ini?
  3. Did you restart Apache and PHP-FPM?
  4. Is post_max_size larger than upload_max_filesize?
  5. Is memory_limit at least as large as post_max_size?
  6. On nginx, did you set client_max_body_size?
  7. Behind Cloudflare or another proxy with its own cap?
  8. Is max_input_time long enough for a slow connection?
Share:

Written by

Amit Verma

Founder / Senior Software Engineer

Amit leads engineering at Being Idea. With 15+ years building scalable software products across global markets, he drives architecture decisions and engineering culture across every engagement.

More articles by Amit

Want to talk tech?

We ship software that scales. Let's work together.

No long-term contracts
Senior engineers only
US · AU · NZ timezone coverage
14-day trial on retainers