Maximale uploadgrootte verhogen in WordPress

WordPress weigert een upload met "exceeds the upload_max_filesize directive" omdat de limiet uit PHP komt, niet uit WordPress. Verhoog upload_max_filesize en post_max_size samen op de juiste plek voor jouw stack, en controleer het resultaat in Site Health.

Je probeert een foto van 12 MB of een korte video naar de mediabibliotheek van WordPress te slepen en de upload sneuvelt met The uploaded file exceeds the upload_max_filesize directive in php.ini. of met een 413-response zonder dat er iets is aangekomen. Het plafond zit niet in WordPress. Het komt uit PHP, en afhankelijk van je stack ook uit de webserver of uit een tweede, aparte Multisite-instelling. Dit artikel legt uit waar de limiet écht vandaan komt en loopt de vijf plekken langs waar je 'm kunt verhogen, met een verificatie aan het eind.

Vereisten. Je hebt één van de volgende nodig: toegang tot je hostingcontrolepaneel (cPanel, Plesk, DirectAdmin, hPanel), SFTP-toegang tot de root van je WordPress-installatie, of SSH-toegang tot de server. Je moet weten welke webserver draait. Dat staat onder Gereedschap > Sitediagnose > Info > Server bij Webserver. Weet je niet welke PHP-handler je host gebruikt (mod_php, PHP-FPM of een managed abstractie)? Kijk dan ook even bij Sitediagnose > Info > Server > PHP SAPI, dat zegt het eigenlijk meteen.

Waar de uploadlimiet vandaan komt

WordPress core heeft geen hardgecodeerd uploadplafond. De effectieve limiet wordt op het moment van de upload berekend door wp_max_upload_size(). Die functie roept ini_get('upload_max_filesize') en ini_get('post_max_size') aan en geeft het kleinste van de twee terug. Met andere woorden: alleen de ene verhogen werkt niet. De laagste waarde wint altijd.

De defaults van PHP zelf, gedocumenteerd in de core INI-directive reference, zijn verrassend laag:

Directive PHP default Scope Waar het over gaat
upload_max_filesize 2M INI_PERDIR Maximale grootte van één geüpload bestand.
post_max_size 8M INI_PERDIR Maximale totale POST-body. Moet groter zijn dan upload_max_filesize.
memory_limit 128M INI_ALL PHP-geheugen per request. Wordt flink gebruikt tijdens thumbnail-generatie.

Die INI_PERDIR-scope is belangrijk. Dat betekent dat upload_max_filesize en post_max_size alleen gezet kunnen worden in php.ini, .htaccess (Apache met mod_php), .user.ini of een PHP-FPM pool-config. Je kunt ze niet vanuit PHP-code op runtime aanpassen. Ik kom daar in de wp-config-sectie op terug, want dat is de fout die ik het vaakst voorbij zie komen.

Boven op PHP heeft de webserver zelf ook nog een plafond op hoe groot een HTTP-request body mag zijn. Apache noemt dat LimitRequestBody. Nginx noemt het client_max_body_size, en de default is 1M. Dat is dus lager dan de PHP-default. De laagste laag wint, dus in de praktijk moet je de waarde soms op twee plekken omhoog zetten ook al denk je alleen maar aan "een PHP-instelling".

Kijk eerst naar je huidige limiet

Voor je iets aanpast: lees de drie waarden uit en kijk welke nu het plafond is. Zo verhoog je alleen de waarde die ertoe doet en kun je achteraf bevestigen dat het écht is gelukt.

De snelste route binnen WordPress is Gereedschap > Sitediagnose > Info > Mediabestanden. Die sectie laat direct Maximale grootte van een bestandsupload zien, rechtstreeks uit wp_max_upload_size(). Staat er 8 MB? Dan is post_max_size je plafond. Staat er 2 MB? Dan is het upload_max_filesize. Alles wat hoger is dan allebei die waarden betekent dat je host de PHP-defaults al voor je heeft verhoogd.

Voor de ruwe getallen kun je een kort diagnosebestandje aanmaken in de root van je WordPress-installatie via de bestandsbeheerder in je hostingpaneel (of via SFTP):

<?php
// upload-check.php, na gebruik weer verwijderen.
echo 'upload_max_filesize: ' . ini_get('upload_max_filesize') . PHP_EOL;
echo 'post_max_size:       ' . ini_get('post_max_size')       . PHP_EOL;
echo 'memory_limit:        ' . ini_get('memory_limit')        . PHP_EOL;
echo 'max_execution_time:  ' . ini_get('max_execution_time')  . PHP_EOL;
echo 'max_input_time:      ' . ini_get('max_input_time')      . PHP_EOL;

Ga naar https://jouwsite.nl/upload-check.php. Verwachte output op een gezonde WordPress-host: upload_max_filesize: 64M, post_max_size: 64M, memory_limit: 256M, max_execution_time: 120, max_input_time: 120. Verwijder het bestand zodra je de getallen hebt. Een phpinfo()-achtig bestand in je document root laten slingeren is sowieso geen goed idee.

De post_max_size-val

Voor je iets verhoogt: snap eerst de relatie tussen de twee bestandsgerelateerde directives. post_max_size moet altijd groter blijven dan upload_max_filesize. Als iemand op een forum zegt dat je upload_max_filesize op 64M moet zetten maar post_max_size op de default 8M laat, dan sneuvelt je upload nog steeds op 8 MB en verspil je een halve middag met zoeken. De PHP-handleiding over common file upload pitfalls is daar duidelijk over: als de POST-body groter is dan post_max_size, dan maakt PHP stilletjes zowel $_POST als $_FILES leeg en geeft de request leeg door aan WordPress. WordPress laat dan een verwarrende lege of mislukte upload-foutmelding zien die helemaal niet op een grootte-fout lijkt.

Mijn vuistregel: zet post_max_size gelijk aan upload_max_filesize, of één stap hoger. 64M en 64M is prima. 64M en 80M is prima. 64M en 8M is een val.

Methode 1: het hostingpaneel (probeer dit eerst)

De meeste managed en shared hosts hebben een PHP-instellingen-editor op paneelniveau. Dat is meteen de schoonste manier om de waarden aan te passen, want het paneel schrijft ze voor jou naar het juiste bestand en de wijziging werkt zonder restart.

  1. Log in op je hostingpaneel.
  2. Open de PHP-instellingeneditor. Bij cPanel zit die onder Software > Select PHP Version > PHP Options, bij oudere cPanels onder MultiPHP INI Editor. Bij Plesk heet hij PHP-instellingen op het Hosting-tabblad van het domein. Bij DirectAdmin is het PHP Selector. Bij hPanel (Hostinger) heet het PHP Configuration.
  3. Zoek upload_max_filesize op en zet 'm op 64M. Heb je een zwaardere use case? Kies dan een realistisch plafond zoals 128M of 256M. Spring niet voor de lol naar 1024M. Een eindig plafond vangt runaway uploads op voordat ze de server plat trekken.
  4. Zoek post_max_size en zet 'm gelijk of één stap hoger.
  5. Zoek memory_limit en zet 'm op minimaal 256M. Beeldverwerking bij een upload kan makkelijk zoveel nodig hebben, en een lage memory limit geeft je een stille crash tijdens thumbnail-generatie terwijl de upload zelf wel is gelukt.
  6. Opslaan. De meeste panelen passen de wijziging toe op de volgende request, zonder restart.

Verwachte output na de wijziging: laad je diagnosebestandje opnieuw. Je weet dat het is aangekomen als de drie waarden staan wat je hebt ingevuld.

Controleer of de upload werkt. Ga naar Media > Nieuwe toevoegen en upload een bestand dat eerder mislukte. Je weet dat de fix houdt als de thumbnail in de bibliotheek verschijnt en je geen HTTP error meer ziet.

Werkt het paneel niet, of staan de waarden er wel maar hebben ze geen effect? Dan heeft je host ze op serverniveau vastgezet. Ga naar methode 2, 3 of 4, afhankelijk van je stack.

Methode 2: .htaccess (alleen Apache met mod_php)

.htaccess is het klassieke advies en tegelijk het advies dat het vaakst stilletjes faalt. De directives hieronder werken alleen op Apache als PHP als Apache-module draait (mod_php). Ze werken niet op Nginx, want Nginx negeert .htaccess volledig. Ze werken ook niet op Apache met PHP-FPM, want php_value is een Apache-naar-PHP-brug die alleen de mod_php-handler snapt. Op die stacks worden de directives gewoon genegeerd en krijg je geen enkel signaal waarom je upload nog steeds mislukt.

Heb je bevestigd dat je Apache met mod_php draait (Sitediagnose toont Apache als webserver en apache2handler als PHP SAPI)? Pas dan .htaccess in de root van je WordPress aan via de bestandsbeheerder in je hostingpaneel of via SFTP:

php_value upload_max_filesize 64M
php_value post_max_size 64M
php_value memory_limit 256M
php_value max_execution_time 300
php_value max_input_time 300

Sla het bestand op. De wijziging werkt op de volgende request. Krijg je meteen na het toevoegen een 500 Internal Server Error? Dan is één van deze drie dingen waar: de server draait geen mod_php, je AllowOverride is te restrictief, of de host heeft php_value in .htaccess gewoon uitgezet. Haal de regels er weer uit en val terug op methode 4 (.user.ini) of het hostingpaneel.

Controleer. Herlaad het diagnosebestandje. Je weet dat het werkt als de waarden staan zoals je ze hebt gezet.

Methode 3: Nginx en PHP-FPM (twee bestanden, niet één)

Voor deze methode heb je SSH-toegang tot je server nodig. Zit je op managed hosting zonder shell-toegang? Gebruik dan methode 1 (het hostingpaneel). Het paneel past de PHP-kant voor je aan, en bij managed Nginx-stacks staat client_max_body_size doorgaans al op een redelijke waarde.

Op de moderne standaardstack (Nginx voor PHP-FPM) moet je de limiet op twee verschillende plekken aanpassen. De ene zet het HTTP-body-plafond op Nginx-niveau. De andere zet de PHP-directives binnen de FPM-pool. Eén vergeten en je upload is nog steeds stuk.

In het Nginx-serverblok (bijv. /etc/nginx/sites-available/jouwsite.conf), op het server-niveau, voeg client_max_body_size toe of verhoog 'm:

server {
    server_name jouwsite.nl;
    root /var/www/jouwsite/current;

    client_max_body_size 80m;

    # ... rest van je config
}

De default is 1M. Een 413 Request Entity Too Large die direct van Nginx komt (zonder WordPress-HTML eromheen) is hét signaal dat deze instelling nog laag staat. Zet de directive op het server-niveau, niet binnen een location. WordPress leunt op URL rewriting via try_files, en een client_max_body_size in een location geldt dan soms niet voor de herschreven request die de upload uiteindelijk afhandelt. Herlaad Nginx met sudo systemctl reload nginx na de wijziging.

In de PHP-FPM pool-config (bijv. /etc/php/8.3/fpm/pool.d/www.conf), voeg de drie PHP-directives toe of verhoog ze:

php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 80M
php_admin_value[memory_limit] = 256M
php_admin_value[max_execution_time] = 300
php_admin_value[max_input_time] = 300

Gebruik php_admin_value in plaats van php_value, zodat een .user.ini of PHP-code deze niet kan overschrijven. Herlaad PHP-FPM met sudo systemctl reload php8.3-fpm (pas de versie aan).

Controleer. Herlaad je diagnosebestandje. Je weet dat de FPM-kant goed zit als upload_max_filesize en post_max_size de nieuwe waarden laten zien. Probeer daarna de upload opnieuw. Je weet dat de Nginx-kant klopt als een bestand dat groter is dan de oude client_max_body_size zonder 413 doorkomt.

Methode 4: .user.ini (PHP-FPM zonder pooltoegang)

Zit je op PHP-FPM maar kun je de pool-config niet bewerken? Dan biedt PHP per-directory .user.ini-bestanden die dezelfde instellingen toepassen binnen die directory. Maak 'm aan in de root van je WordPress (naast wp-config.php) via de bestandsbeheerder in je hostingpaneel of via SFTP:

upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M

PHP scant .user.ini-bestanden opnieuw op een interval dat wordt bepaald door user_ini.cache_ttl, standaard 300 seconden. Wijzigingen kunnen dus tot vijf minuten duren voordat ze aanslaan, en dat is veruit de meest voorkomende reden dat mensen denken dat .user.ini niet werkt. Wacht de cache uit en lees dan het diagnosebestandje opnieuw.

.user.ini respecteert de INI_PERDIR-scope van upload_max_filesize en post_max_size, wat wp-config.php niet doet. Dit is dus het juiste gereedschap als je alleen filesystem-toegang hebt en geen paneel.

Methode 5: wp-config.php (waarom ini_set hier niet werkt)

Hier gaat het advies op de meeste forums mis. Een populaire snippet ziet er zo uit:

// Dit werkt niet. Niet gebruiken.
@ini_set( 'upload_max_filesize' , '64M' );
@ini_set( 'post_max_size',   '64M');

Ziet er logisch uit. Draait zonder fout. De ini_set()-call geeft zelfs netjes iets terug. De waarde heeft geen enkel effect. De reden is die INI_PERDIR-scope. De eigen documentatie van PHP bij ini_set() is er expliciet over: INI_PERDIR-directives kun je alleen zetten in php.ini, .htaccess, .user.ini of een PHP-FPM pool-config. Op runtime zijn ze read-only. Tegen de tijd dat de upload überhaupt in PHP is aangekomen, is het bestand al geaccepteerd of geweigerd op basis van de waarde die vóór het script werd gelezen. ini_set() erop aanroepen is puur cosmetisch.

Wat wp-config.php wél legitiem mag doen, is memory_limit verhogen, want memory_limit is INI_ALL (geen INI_PERDIR). Daarmee kun je een laag geheugenplafond tijdens beeldverwerking omzeilen, zelfs als je de upload-limiet niet kunt raken:

// Verhoog het WordPress memory limit. Veilig in wp-config.php.
define( 'WP_MEMORY_LIMIT', '256M' );
define( 'WP_MAX_MEMORY_LIMIT', '512M' );

De eerste regel werkt op front-end-requests. De tweede op wp-admin. WordPress vertaalt dit bootstrap-gewijs naar een ini_set('memory_limit', ...). Ze staan allebei in mijn naslag over wp-config.php-instellingen, samen met de andere constanten die wel en niet in dat bestand thuishoren.

Als je jezelf betrapt op ini_set('upload_max_filesize', ...) in wp-config.php of in een must-use plugin: stop en pak één van de andere vier methodes. Voor deze directive bestaat er geen shortcut via PHP-code.

Methode 6: het upload_size_limit-filter (alleen verlagen)

WordPress biedt een upload_size_limit-filter waarmee je het effectieve plafond vanuit code kunt bijstellen. Handig als je een lager plafond wilt voor bepaalde gebruikers (een limiet voor redacteuren, geen limiet voor beheerders), of als je een duidelijkere foutmelding wilt tonen voordat de upload überhaupt begint.

Eén belangrijke randvoorwaarde: het filter kan het plafond alleen verlagen, nooit verhogen. Zegt PHP 64M en geeft het filter 128M terug? Dan weigert de server de upload nog steeds op 64 MB, want PHP heeft zijn werk al gedaan. Een lagere waarde teruggeven laat WordPress wel vooraf checken en keurt de upload af in JavaScript met een heldere melding.

Een voorbeeld per rol, in een mu-plugin op wp-content/mu-plugins/upload-limits.php:

<?php
// Beperk uploads van niet-admins tot 10 MB.
add_filter( 'upload_size_limit', function( $size, $u_bytes, $p_bytes ) {
    if ( current_user_can( 'manage_options' ) ) {
        return $size;
    }
    return 10 * 1024 * 1024;
}, 10, 3 );

Het filter krijgt drie argumenten: het berekende effectieve plafond in bytes, upload_max_filesize in bytes en post_max_size in bytes. Geef een integer in bytes terug om het effectieve plafond te wijzigen.

WordPress Multisite heeft een tweede plafond

Dit is de stap die mensen bij Multisite altijd vergeten. Ook al heb je PHP en de webserver op 64M-uploads gezet, Multisite hanteert een apart netwerk-breed plafond dat standaard op 1.500 KB (ongeveer 1,5 MB) staat. Die waarde zit in de fileupload_maxk-site-optie en wordt toegepast door upload_size_limit_filter(), die op elke Multisite-installatie automatisch in upload_size_limit haakt.

Om 'm te verhogen: ga naar Netwerk-beheer > Instellingen > Netwerkinstellingen > Upload-instellingen > Maximale bestandsgrootte uploads en pas de waarde aan. De eenheid op het formulier is kilobytes, dus 64M is 65536 (64 × 1024).

Drie regels om te onthouden:

  • Het Multisite-plafond kan nooit boven het PHP-plafond uit. Zet je Netwerk-beheer op 65536 maar staat PHP nog op 2M? Dan wint PHP.
  • Individuele sites in het netwerk kunnen niet boven de netwerk-brede waarde uit.
  • Heb je PHP verhoogd maar stoppen uploads nog steeds op het oude 1,5 MB-plafond? Dan is het Multisite-filter de oorzaak. Dat is geen bug. Dat is upload_size_limit_filter() die gewoon zijn werk doet.

De Big Image Threshold is geen uploadlimiet

Dit is het meest voorkomende misverstand na de PHP-val. Sinds WordPress 5.3 kent core de big image size threshold, die foto's met afmetingen boven 2560 pixels na de upload verkleint. Mensen denken weleens dat dit is wat de upload limiteert. Dat klopt niet. Het volledige originele bestand wordt eerst geüpload en opgeslagen. Daarna maakt WordPress een verkleinde kopie (opgeslagen als jouwbestand-scaled.jpg) en gebruikt die als primaire afbeelding in de bibliotheek. Het origineel blijft op schijf staan en is bereikbaar via wp_get_original_image_path().

Twee praktische gevolgen:

  • Dit blokkeert uploads niet. Een JPEG van 20 MB wordt volledig geüpload, threshold of niet.
  • Het raakt wel je geheugen. Het genereren van thumbnails en de verkleinde kopie laadt de afbeelding ongecomprimeerd in het geheugen. Een 24-bits afbeelding van 6000 × 4000 pixels heeft ruwweg 72 MB aan bitmap nodig, plus PHP-overhead. Daarom is memory_limit verhogen belangrijk voor grote uploads: de upload zelf lukt, maar de verwerkingsstap daarna klapt met Allowed memory size exhausted. Het aparte artikel over allowed memory size exhausted gaat op dat scenario in.
  • PNG-bestanden worden uitgesloten van het verkleinen. WordPress slaat de scaling-stap voor PNG's bewust over, omdat een PNG-8 met indexed colors bij het resizen via GD wordt opgewaardeerd naar PNG-24/32 en dan juist groter uit de bus komt dan het origineel. Upload je dus een grote PNG? Dan blijft het origineel ongewijzigd in de bibliotheek staan, zonder dat er een -scaled-kopie naast wordt gemaakt.

Wil je de threshold helemaal uitzetten of naar 4000 pixels optrekken? Dan is dit het filter:

// Verhoog de big image threshold naar 4000 pixels.
add_filter( 'big_image_size_threshold', function() {
    return 4000;
});

Geef false terug uit hetzelfde filter om het verkleinen helemaal uit te zetten. Zet dit in een mu-plugin, niet in functions.php, zodat een theme switch het niet meeneemt.

Controleer het eindresultaat

Welke methode je ook hebt gebruikt, loop aan het eind dezelfde drie checks af:

  1. Herlaad je diagnosebestandje in de root van WordPress en bevestig dat upload_max_filesize, post_max_size en memory_limit staan op wat je hebt gezet.
  2. Ga naar Gereedschap > Sitediagnose > Info > Mediabestanden en bevestig dat Maximale grootte van een bestandsupload de nieuwe waarde laat zien.
  3. Upload het originele probleembestand via Media > Nieuwe toevoegen. Je weet dat de fix houdt als de thumbnail verschijnt, de statuscode in het netwerktabblad van je browser op async-upload.php een 200 is, en het bestand in de mediabibliotheek staat zonder HTTP error.

Verwijder het diagnosebestandje zodra je klaar bent.

Als het nog steeds stuk is

Heb je de limiet op alle juiste plekken omhoog gezet en mislukt de upload nog steeds? Dan is het vrijwel zeker niet meer het grootteplafond. De meest voorkomende vervolgmeldingen zijn:

  • Een generieke HTTP error in de mediabibliotheek zonder duidelijke oorzaak. Het aparte artikel over HTTP-fout bij media-uploads loopt de diagnose per statuscode langs, legt uit hoe je het netwerktabblad leest en gaat in op de vijf dingen die deze fout in de praktijk veroorzaken.
  • Een Fatal error: Maximum execution time of N seconds exceeded tijdens een langzame upload over een trage verbinding. Dit is een andere timer. De fix staat in het artikel over maximum execution time exceeded, waar ook het verschil tussen max_execution_time en max_input_time wordt uitgelegd (die laatste is de timer die bij grote uploads het vaakst trippet en standaard wordt vergeten).
  • Een PHP-fatal tijdens de thumbnail-generatie. Volg dan het artikel over allowed memory size exhausted om de geheugenkant netjes op te lossen.

Heb je een terugkerende workflow met grote uploads? Denk dan ook even aan de optie die geen PHP-instelling is: upload het bestand via SFTP direct naar wp-content/uploads/ en registreer het daarna als media-attachment met wp media import of de plugin "Add from Server". Die route omzeilt elke limiet uit dit artikel, in ruil voor één extra stap. Het is het juiste gereedschap als je een eenmalige batch zware video's of drukklare pdf's moet importeren en geen zin hebt om aan serverconfiguratie te gaan zitten.

WordPress onderhoud zonder omkijken?

Ik regel updates, backups en beveiliging, en houd performance strak—zodat storingen en traagheid niet terugkomen.

Bekijk WordPress onderhoud

Doorzoek deze site

Begin met typen om te zoeken, of blader door de kennisbank en blog.