Shared hosting limieten staan zelden op de pagina met pakketten: „onbeperkt” slaat meestal op dataverkeer, websites of mailboxen, niet op serverresources, en de helppagina’s van grote providers noemen een limiet op het aantal bestanden (inodes), een aantal gelijktijdige PHP-processen, een CPU-aandeel, geheugen, databaseverbindingen en e-mails per uur. De limieten waar een site als eerste tegenaan loopt, zijn meestal gelijktijdige PHP-processen en CPU: bezoekers zien trage laadtijden en daarna 503, 504 of 508 „Resource Limit Is Reached”. Hieronder vind je de gepubliceerde limieten van vijf bekende hosts, een test op onze testopstelling en een script dat je eigen limieten vanuit PHP laat zien.
Hoe we het hebben gecontroleerd
Op 10 november 2026 hebben we de gepubliceerde limieten en gebruiksvoorwaarden van Hostinger, Bluehost, SiteGround, Namecheap en HostGator gelezen (links in de tabel). Dezelfde dag hebben we op een testopstelling (Ubuntu 24.04.5 container, 2 vCPU, nginx 1.24.0, PHP-FPM 8.3.6, MariaDB 10.11.14) typische limieten nagebootst: een PHP-FPM-pool met pm.max_children = 4, timeouts, uploadlimieten, MAX_USER_CONNECTIONS 3 voor de databasegebruiker en CPU- en geheugenplafonds via cgroups, hetzelfde kernelmechanisme waarop de LVE-limieten van CloudLinux zijn gebouwd (CloudLinux zelf draaide niet op de testopstelling). Dit zijn testresultaten, geen cijfers van de servers van RichHost.
Wat de voorwaarden van „onbeperkte” pakketten echt zeggen
„Onbeperkt” verwijst naar wat de provider niet meet: dataverkeer, het aantal domeinen, soms schijfruimte. Technische resources zijn altijd beperkt, omdat honderden accounts één server delen; het enige verschil is of de provider de cijfers publiceert. Dit staat er op de officiële helppagina’s:
| Provider, pakketten | Bestanden (inodes) | Gelijktijdige PHP-processen | CPU | E-mail vanaf de server | Database |
|---|---|---|---|---|---|
| Hostinger: Single / Premium / Business (verkocht als Unlimited) | 200.000 / 400.000 / 600.000 | 20 / 40 / 60 PHP workers | 1 / 1 / 2 cores | 10 per minuut, tot 100 per dag | 3 GB; 25 / 50 / 75 verbindingen; queries tot 60 / 60 / 120 s |
| Bluehost: shared | maximaal 200.000, zachte drempel 50.000 | niet gepubliceerd | beperkt, zonder cijfers | vanaf 200 per uur (tot 1.000 bij hogere niveaus) | 5 GB per database, 10 GB in totaal |
| SiteGround: StartUp / GrowBig / GoGeek | 200.000 / 400.000 / 600.000 | niet gepubliceerd | 1.000 / 2.000 / 4.000 CPU-seconden per uur | niet gepubliceerd | tot 1.000 MB per database |
| Namecheap: Stellar / Stellar Plus / Stellar Business | 300.000 / 300.000 / 600.000 | 20 / 30 / 40 entry processes | 50 / 50 / 100% van een core | 50 / 200 / 10.000 per uur per domein | niet gepubliceerd |
| HostGator: shared | 1.000.000 bestanden | 25 gelijktijdige processen | 25% CPU | 500 per uur | 5 GB; 25 verbindingen |
Details die je makkelijk over het hoofd ziet. Op de inodepagina van Bluehost staat dat een account boven 200.000 bestanden onder het onderdeel over overmatig resourcegebruik van het beleid valt en dat boven 1.000.000 opschorting mogelijk is. Namecheap sluit accounts met meer dan 200.000 inodes uit van automatische back-ups (behalve Stellar Business). SiteGround raadt aan dezelfde cronjob niet vaker dan elke 30 minuten te draaien en beperkt een proces tot 768 MB geheugen. Hostinger noemt daarnaast een PHP max_execution_time van 360 s en een maximale duur voor databasequeries. Het vroegere A2 Hosting (nu hosting.com) belooft op de pakkettenpagina geen „onbeperkt” meer en publiceert daar geen limietcijfers.
CloudLinux, dat op een groot deel van de shared hosting servers draait, gebruikt volgens de documentatie van CloudLinux deze standaardwaarden: één CPU-core (SPEED 100%), 1024 MB fysiek geheugen (PMEM), 20 entry processes (EP), in totaal 100 processen (NPROC), 1024 KB/s schijf-I/O. Een provider kan elk van deze waarden aanpassen.
Welke limieten als eerste knellen en hoe dat eruitziet
Sommige limieten geven meteen een fout, andere maken de site alleen trager, en weer andere breken een functie zonder dat er een fout op het scherm verschijnt. De tabel combineert onze tests met de documentatie van CloudLinux:
| Limiet | Wat de bezoeker ziet | Waar je het spoor vindt |
|---|---|---|
| Gelijktijdige PHP-processen (EP, PHP workers, pm.max_children) | Een wachtrij, daarna 504; op CloudLinux 508 Resource Limit Is Reached | Grafiek van entry processes in het paneel; regel „server reached max_children setting” in het PHP-FPM-log |
| CPU (SPEED, CPU-seconden) | De site is gewoon trager, zonder fout | CPU-grafiek in het paneel, oplopende responstijd |
| Geheugen van het account (PMEM) | 500, 502 of 503, niets in het PHP-log | Proces gestopt met SIGKILL, geheugengrafiek |
| PHP memory_limit | 500 of de WordPress-pagina „kritieke fout” | error_log: Allowed memory size exhausted |
| max_execution_time | 500 na een paar seconden werk | error_log: Maximum execution time exceeded |
| Timeout van proxy of PHP-FPM | 504 Gateway Time-out of 502 Bad Gateway | error.log van de webserver |
| upload_max_filesize, post_max_size | De pagina geeft 200, maar het bestand ontbreekt; of 413 | Foutcode 1 in $_FILES, waarschuwing over POST Content-Length |
| Inodes | Nieuwe bestanden kunnen niet worden aangemaakt: cache, sessies, thumbnails, mail | No space left on device terwijl de schijf nog ruimte heeft |
| MySQL max_user_connections | Error establishing a database connection | ERROR 1226 in het log |
Uitgebreide uitleg over losse gevallen: de fout 508 Resource Limit Is Reached, memory_limit verhogen en de inode-limiet bij hosting.
Test: wat krijgt de vijfde bezoeker als er vier PHP-processen zijn
We hebben een PHP-FPM-pool met vier processen ingericht en een pagina die 5 seconden wacht, zoals een pagina die wacht op een trage externe API of een zware databasequery. Daarna stuurden we tegelijk verzoeken:
- 5 verzoeken: de eerste vier antwoordden na 5,0 s, de vijfde na 9,8 s. Geen fout: het verzoek wachtte gewoon in de wachtrij op een vrij proces. In het PHP-FPM-log verscheen de regel
server reached max_children setting (4), consider raising it. - 12 verzoeken met een proxytimeout van 10 s: verzoeken 1 tot en met 4 kregen 200 na 5,0 s, 5 tot en met 8 kregen 200 na 9,8 s, 9 tot en met 12 kregen 504 Gateway Time-out na precies 10 s.
- Spoken na een 504: direct na die golf openden we de lichtste pagina. Die deed er 3,75 s over in plaats van meteen te antwoorden, omdat alle vier processen nog bezig waren met verzoeken waarvan de bezoekers al een 504 hadden gekregen.
De les: de limiet op gelijktijdigheid gaat niet over het aantal bezoekers, maar over het aantal trage verzoeken. Vier processen bedienen tientallen mensen als een pagina in 0,1 s klaar is, en lopen vast bij de vijfde als elke pagina 5 seconden op een externe dienst wacht. Op CloudLinux krijgt een bezoeker die de EP-limiet raakt meteen een 508, zonder wachtrij. Hoe je veilig je eigen plafond vindt, lees je in onze handleiding over een loadtest van een website.
CPU: geen fout, maar vertraging
We draaiden dezelfde pagina met een vaste hoeveelheid rekenwerk onder een CPU-plafond via cgroup. Alle 120 verzoeken gaven 200; alleen de tijd veranderde:

Vier gelijktijdige verzoeken delen één quotum, dus bij 25% van een core deed een pagina die zonder plafond in 0,35 s antwoordde er gemiddeld 3,83 s over. Zo ziet „de site is traag, maar het paneel zegt dat alles werkt” eruit.
Timeouts: drie verschillende klokken
max_execution_timetelt op Linux de CPU-tijd van het script. Een rekenlus met een limiet van 3 s eindigde met een 500 enMaximum execution time of 3 seconds exceeded, terwijl een pagina die onder dezelfde limiet 6 s wachtte (sleep) 200 teruggaf. Wachten op een API of de database telt niet mee.request_terminate_timeoutin PHP-FPM telt de werkelijk verstreken tijd: zowel rekenen als wachten werd na 20 s afgebroken en de bezoeker kreeg 502.- De proxytimeout (
fastcgi_read_timeoutin nginx) gaf na 10 s een 504, hoewel PHP gewoon doorliep.
Geheugen, uploads en de database
- 200 MB reserveren met
memory_limit = 128Mgaf een 500 en een regel in het PHP-log. Toen we het geheugen van de hele pool op 256 MB begrensden (zoals PMEM in LVE) en memory_limit naar 1024M verhoogden, stopte de kernel het proces: 502 en geen enkele regel in het PHP-log. - Een bestand van 3 MB met
upload_max_filesize = 2M: de pagina gaf 200, maar het bestand kwam nooit aan (foutcode 1). Een bestand van 9 MB metpost_max_size = 8M: het hele formulier verdween, tekstvelden inbegrepen. Hetzelfde bestand van 3 MB via nginx met standaardinstellingen: 413 Request Entity Too Large. - Een databasegebruiker met
MAX_USER_CONNECTIONS 3: van vijf gelijktijdige verzoeken kregen er twee binnen 0,002 sERROR 1226 ... has exceeded the 'max_user_connections' resource. WordPress toont in dat geval „Error establishing a database connection”. Een limiet op de queryduur (max_statement_time = 2) brak een zware query na precies 2 s af met ERROR 1969.
Zo controleer je je limieten: het script limits.php
Het hostingpaneel laat niet alles zien. We hebben het script hieronder op de testopstelling in twee modi getest: met een gewone pool en met een pool waarin shellfuncties zijn uitgeschakeld en open_basedir actief is, zoals bij veel shared hosts. Het toont de werkelijk geldende PHP-waarden, de grootst mogelijke upload, het CPU-aandeel dat het script in 1 seconde echt krijgt, proceslimieten uit /proc en cgroup (als die leesbaar zijn), ulimit -a (als shell is toegestaan), het aantal bestanden in je homedirectory en de databaselimieten, inclusief MAX_USER_CONNECTIONS uit GRANT.
- Vervang
KEYdoor je eigen lange tekenreeks. - Upload het bestand naar de hoofdmap van de site, naast wp-config.php (vul bij een ander CMS de array
$dbin). - Open
https://your-site/limits.php?key=YOUR_KEY. Zonder sleutel geeft het script 404. - Bewaar de uitvoer en verwijder het bestand meteen.
<?php
// limits.php: shows the limits that really apply to this hosting account.
// 1) set your own KEY, 2) upload next to wp-config.php (or fill DB_* below),
// 3) open https://your-site/limits.php?key=YOUR_KEY, 4) DELETE the file afterwards.
const KEY = 'change-me';
$db = ['host' => '', 'user' => '', 'pass' => '', 'name' => '']; // empty = read wp-config.php
if (KEY === 'change-me' || !hash_equals(KEY, (string)($_GET['key'] ?? ''))) { http_response_code(404); exit; }
header('Content-Type: text/plain; charset=utf-8');
function row($k, $v) { printf("%-28s %s\n", $k, is_bool($v) ? ($v ? 'yes' : 'no') : $v); }
function head($t) { echo "\n== $t\n"; }
function bytes($v) { $n = (float)$v; $u = strtolower(substr(trim($v), -1)); return $u === 'g' ? $n * 1073741824 : ($u === 'm' ? $n * 1048576 : ($u === 'k' ? $n * 1024 : $n)); }
function readable($f) { return @is_readable($f) ? trim((string)@file_get_contents($f)) : null; }
head('PHP');
row('version / SAPI', PHP_VERSION . ' / ' . PHP_SAPI);
foreach (['memory_limit', 'max_execution_time', 'max_input_time', 'upload_max_filesize', 'post_max_size',
'max_file_uploads', 'max_input_vars', 'default_socket_timeout', 'open_basedir', 'disable_functions',
'opcache.enable', 'opcache.memory_consumption', 'sendmail_path'] as $k) {
$v = ini_get($k);
row($k, $v === false ? '(not available)' : ($v === '' ? '(empty)' : $v));
}
$up = min(bytes(ini_get('upload_max_filesize')), bytes(ini_get('post_max_size')) ?: PHP_INT_MAX);
row('largest upload via PHP', round($up / 1048576, 1) . ' MB (web server may allow less)');
head('This process');
$u = function_exists('posix_getpwuid') ? (posix_getpwuid(posix_geteuid())['name'] ?? '?') : get_current_user();
row('pid / user', getmypid() . ' / ' . $u);
$t0 = microtime(true); $r0 = getrusage(); $n = 0;
while (microtime(true) - $t0 < 1.0) { $n++; } // 1 s of pure CPU work
$r1 = getrusage(); $wall = microtime(true) - $t0;
$cpu = ($r1['ru_utime.tv_sec'] + $r1['ru_utime.tv_usec'] / 1e6 + $r1['ru_stime.tv_sec'] + $r1['ru_stime.tv_usec'] / 1e6)
- ($r0['ru_utime.tv_sec'] + $r0['ru_utime.tv_usec'] / 1e6 + $r0['ru_stime.tv_sec'] + $r0['ru_stime.tv_usec'] / 1e6);
row('CPU test 1 s', sprintf('cpu %.2f s of wall %.2f s = %d%% (loops %s)', $cpu, $wall, 100 * $cpu / $wall, number_format($n)));
row('peak memory', round(memory_get_peak_usage(true) / 1048576, 1) . ' MB');
row('max RSS (getrusage)', round($r1['ru_maxrss'] / 1024, 1) . ' MB');
head('OS limits (/proc, cgroup)');
if ($l = readable('/proc/self/limits')) {
foreach (explode("\n", $l) as $line) {
if (preg_match('/^(Max cpu time|Max processes|Max open files|Max address space)\s+(\S+)\s+(\S+)/', $line, $m)) row($m[1], "soft $m[2], hard $m[3]");
}
} else { row('/proc/self/limits', 'not readable (open_basedir?)'); }
foreach (explode("\n", (string)readable('/proc/self/cgroup')) as $line) { // own cgroup (v1 and v2)
$p = explode(':', $line, 3); if (count($p) < 3) continue;
$files = $p[1] === '' ? ['memory.max', 'cpu.max', 'pids.max'] : ['memory' => ['memory.limit_in_bytes'],
'cpu' => ['cpu.cfs_quota_us', 'cpu.cfs_period_us'], 'pids' => ['pids.max']][$p[1]] ?? [];
foreach ($files as $f) {
$path = '/sys/fs/cgroup' . ($p[1] === '' ? '' : '/' . $p[1]) . rtrim($p[2], '/') . '/' . $f;
if (($v = readable($path)) !== null) row("cgroup $f", $v);
}
}
$fn = 'shell_exec';
if (function_exists($fn) && !in_array($fn, array_map('trim', explode(',', (string)ini_get('disable_functions'))), true)) {
head('ulimit -a (shell)');
echo $fn('ulimit -a 2>&1') ?: "(no output)\n";
} else { row('shell_exec', 'disabled'); }
head('Files (inodes)');
$home = getenv('HOME') ?: dirname(__DIR__);
$base = @is_readable($home) ? $home : __DIR__;
$cnt = 0; $stop = microtime(true) + 15;
try {
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($base, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD);
foreach ($it as $x) { $cnt++; if (microtime(true) > $stop) { $cnt .= '+ (stopped after 15 s)'; break; } }
} catch (Throwable $e) { $cnt .= ' (error: ' . $e->getMessage() . ')'; }
row('files+dirs under', "$base: $cnt");
row('disk free (volume)', round(@disk_free_space(__DIR__) / 1073741824, 1) . ' GB (volume, not your quota)');
head('Database');
if ($db['user'] === '' && is_readable(__DIR__ . '/wp-config.php')) {
$c = file_get_contents(__DIR__ . '/wp-config.php');
foreach (['host' => 'DB_HOST', 'user' => 'DB_USER', 'pass' => 'DB_PASSWORD', 'name' => 'DB_NAME'] as $k => $c2)
if (preg_match("/define\(\s*['\"]{$c2}['\"]\s*,\s*['\"](.*?)['\"]\s*\)/", $c, $m)) $db[$k] = $m[1];
}
if ($db['user'] === '' || !class_exists('mysqli')) { row('database', 'no credentials or no mysqli'); exit; }
mysqli_report(MYSQLI_REPORT_OFF);
$h = $db['host'] ?: 'localhost'; $port = null; $sock = null;
if (strpos($h, ':') !== false) { [$h, $p] = explode(':', $h, 2); is_numeric($p) ? $port = (int)$p : $sock = $p; }
$m = @new mysqli($h, $db['user'], $db['pass'], $db['name'], $port, $sock);
if ($m->connect_errno) { row('connect error', $m->connect_errno . ' ' . $m->connect_error); exit; }
$q = $m->query('SELECT VERSION() v, @@max_connections mc, @@max_user_connections muc, @@wait_timeout wt, @@max_allowed_packet map');
foreach ($q->fetch_assoc() as $k => $v) row(['v' => 'server version', 'mc' => 'max_connections (server)',
'muc' => 'max_user_connections', 'wt' => 'wait_timeout', 'map' => 'max_allowed_packet'][$k], $v);
foreach (['@@max_statement_time' => 'max_statement_time (MariaDB)', '@@max_execution_time' => 'max_execution_time (MySQL, ms)'] as $var => $label)
if ($r = $m->query("SELECT $var")) row($label, $r->fetch_row()[0]);
if ($r = $m->query('SHOW GRANTS FOR CURRENT_USER()')) {
while ($g = $r->fetch_row()) if (preg_match('/WITH (.*)$/', $g[0], $mm)) row('per-user limits (GRANT)', $mm[1]);
}
if ($r = $m->query('SELECT COALESCE(ROUND(SUM(data_length+index_length)/1048576,1),0) FROM information_schema.tables WHERE table_schema = DATABASE()'))
row('this database size', $r->fetch_row()[0] . ' MB');
echo "\nDone. Delete this file now.\n";
Op de testopstelling met een CPU-plafond van 25% luidde de testregel CPU test 1 s cpu 0.27 s of wall 1.04 s = 26%, en verderop toonde het script het quotum zelf: cgroup cpu.cfs_quota_us 25000. Zonder quotum maar op een drukke machine gaf de test 70%: een laag percentage kan ook door buren komen, dus lees beide regels samen. Op CloudLinux-servers zijn de cgroup-bestanden vanuit een account meestal niet leesbaar; vertrouw dan op de CPU-test en de grafieken in het paneel. Hoe je PHP controleert of wisselt, lees je in onze handleiding over de PHP-versie bij je hosting.
Twee dingen kan het script niet laten zien: de e-maillimiet per uur (die kent alleen de mailserver van de provider) en het kortste cron-interval. Vraag beide na bij support; het instellen van taken staat in onze handleiding over cronjobs op hosting.
Als X, doe dan Y
| Als | Doe dan |
|---|---|
| Af en toe 508 of 503, en het log noemt max_children of de EP-limiet | Zoek de trage verzoeken (slowlog, Query Monitor) en zet paginacaching aan; meer processen zonder dat stellen het probleem alleen uit |
| De site is traag zonder fouten en de CPU-grafiek raakt het plafond | Paginacache, OPcache, zware plugins weghalen; is dat niet genoeg, dan een groter pakket |
| 504 tijdens import, export of back-up | Draai zulke taken in porties via cron of WP-CLI, niet vanuit de browser |
| 500 en „Allowed memory size exhausted” | Verhoog memory_limit binnen het pakket en zoek uit wat het geheugen opslokt |
| 502 of 503 en niets in het PHP-log | Verdenk de geheugenlimiet van het account en neem contact op met support met het exacte tijdstip van de fout |
| Een bestand wordt niet geüpload en er is geen fout | Vergelijk upload_max_filesize, post_max_size en de limiet van de webserver: de kleinste wint |
| „Error establishing a database connection” onder belasting | Controleer MAX_USER_CONNECTIONS, verwijder lange queries en persistente verbindingen |
| Nieuwe bestanden kunnen niet worden aangemaakt terwijl er schijfruimte is | Tel de inodes, ruim cache, sessies en oude back-ups op |
Hoe het bij RichHost werkt
De hostingpakketten van RichHost bevatten onbeperkt dataverkeer en een onbeperkt aantal websites, mailboxen en FTP-accounts op NVMe-schijven. Mail gaat de deur uit vanaf schone IP-adressen, de bezorging wordt bewaakt en spammers worden geblokkeerd; bulkmailings verstuur je daarom het best via een aparte dienst. Vraag support naar de exacte limieten voor processen, geheugen en bestanden van een bepaald pakket: support werkt van 10:00 tot 20:00 uur Kyiv-tijd en antwoordt binnen ongeveer 30 minuten. Het script hierboven laat zien wat er echt voor jouw account geldt.
Veelgestelde vragen
Wat is het verschil tussen 503, 504 en 508?
Op CloudLinux betekent 508 dat het account geen gelijktijdige processen meer over heeft. 503 heeft vaker te maken met geheugen of het aantal processen. 504 betekent dat de proxy niet op tijd een antwoord van PHP kreeg.
Kan ik de limieten verhogen zonder van pakket te wisselen?
PHP-waarden (memory_limit, max_execution_time, uploadgrootte) kun je vaak in het paneel aanpassen binnen het pakket. CPU, accountgeheugen en proceslimieten bepaalt de provider; die veranderen alleen met een ander pakket.
Is het veilig om limits.php op de site te laten staan?
Nee. Het script verraadt instellingen van de server en de database. Draai het met je eigen sleutel, bewaar de uitvoer en verwijder het bestand.



