← Terug naar kennisbank HOSTING

Warning: mysqli_ — foutmeldingen uitgelegd en opgelost

Plotseling staat je site vol met rode Warning: mysqli_… meldingen, of erger: er komt niets meer door behalve een witte pagina. Deze gids loopt alle veelvoorkomende mysqli-foutmeldingen door — letterlijk de tekst die je in je scherm of error_log ziet — en legt uit wat de oorzaak is en hoe je 'm oplost.

De mysqli_* functies zijn de moderne MySQL-interface voor PHP. Ze vervingen in PHP 5.5 (en definitief in PHP 7.0) de oude mysql_* familie. Vrijwel elk Nederlands CMS — WordPress, Joomla, Drupal, OpenCart, CMS Made Simple en duizenden custom-PHP-sites — gebruikt mysqli onder de motorkap.

Als je een Warning: mysqli_… melding ziet, is er één van vier dingen aan de hand: de databaseverbinding faalt, een query mislukt waarna de code blind doorgaat, je hosting/PHP-versie is gewijzigd, of er is een datatype-mismatch sinds PHP 8. Hieronder elk scenario met de letterlijke foutmelding zoals 'ie in jouw scherm of error_log verschijnt.

Belangrijk: zet eerst display_errors uit op productie

Voor we beginnen: als bezoekers van je site die warnings letterlijk in beeld zien, lekt je site mogelijk database-credentials, paden naar bestanden en versie-informatie. Eerste actie:

// In wp-config.php (WordPress) / configuration.php (Joomla)
// of bovenin je custom PHP-bestand:
ini_set('display_errors', 0);
ini_set('log_errors', 1);
error_reporting(E_ALL);

Zo blijven fouten zichtbaar in je error_log (waar je ze kunt debuggen), maar niet meer voor bezoekers of zoekmachines. Daarna pas oplossen.

Verbindingsfouten — mysqli_connect()

Dit is veruit de meest voorkomende categorie. De error verschijnt zodra PHP probeert verbinding met de database te maken en dat mislukt. Op een WordPress-site krijg je dan vaak ook de bekende melding "Error establishing a database connection".

Warning: mysqli_connect(): (HY000/1045): Access denied for user 'xxx'@'localhost'

Inlog-fout. De gebruikersnaam, wachtwoord of host-instelling klopt niet. Mogelijke oorzaken:

  • Verkeerd wachtwoord in wp-config.php, configuration.php of je eigen config.php
  • Database-wachtwoord gewijzigd in het hosting control panel zonder dat het bestand is bijgewerkt
  • Verkeerde gebruiker: het account bestaat wel, maar heeft geen rechten op deze database
  • Verkeerde host: lokaal vaak localhost, bij sommige hosters is het mysql.jouwdomein.nl of een specifieke server zoals db123.hostnet.nl
  • Speciale tekens in het wachtwoord: een $, " of backslash kan in PHP-strings problemen geven — gebruik '-quotes of escape correct

Fix: open je config-bestand, controleer de vier waarden (DB_NAME, DB_USER, DB_PASSWORD, DB_HOST) en vergelijk ze 1-op-1 met wat in je control panel staat. Reset desnoods het wachtwoord en kopieer het exact over.

Warning: mysqli_connect(): (HY000/2002): No such file or directory

PHP probeert verbinding te maken via een Unix socket die niet bestaat. Dit is bijna altijd: je hebt localhost ingesteld als host, terwijl je hoster verwacht dat je via TCP/IP verbinding maakt naar een specifieke hostname.

Fix: vervang localhost door 127.0.0.1, of door de databasehost die je hoster opgeeft (bijvoorbeeld mysql.jouwdomein.nl). Het verschil:

  • localhost → PHP probeert via een Unix socket bestand
  • 127.0.0.1 → PHP gebruikt TCP-netwerk (vaak op poort 3306)
  • db.hoster.nl → externe databaseserver, altijd TCP

Warning: mysqli_connect(): (HY000/2002): Connection refused

De databaseserver weigert de verbinding actief. Mogelijke oorzaken:

  • MySQL-service draait niet (vooral op je eigen server / VPS) — herstart MySQL/MariaDB
  • Verkeerde poort: standaard is 3306, maar sommige hosters gebruiken 3307 of een unieke poort per klant
  • Firewall blokkeert de verbinding tussen webserver en database (vooral bij externe DB's)
  • MySQL is overbelast en weigert nieuwe connecties tijdelijk

Op shared hosting: vaak een tijdelijke storing — refresh een paar keer, en kijk eventueel op de status-pagina van je hoster.

Warning: mysqli_connect(): (HY000/2002): Connection timed out

De databaseserver reageert niet binnen de timeout. Op shared hosting zelden — vrijwel altijd hosting-side. Bij externe databases (bijvoorbeeld AWS RDS of een DB op een andere server) is meestal het netwerk of een security group de oorzaak.

Warning: mysqli_connect(): (HY000/1044): Access denied for user 'xxx'@'%' to database 'yyy'

De gebruiker bestaat en het wachtwoord klopt — maar deze user heeft geen rechten op deze specifieke database. Komt vooral voor na migraties: je nieuwe database is klantnaam_db1, maar je wp-config.php wijst nog naar klantnaam_db. Fix: pas DB_NAME aan, of geef de juiste gebruiker rechten via GRANT in phpMyAdmin.

Warning: mysqli_connect(): (HY000/1040): Too many connections

De database accepteert tijdelijk geen nieuwe connecties meer omdat het maximum bereikt is. Twee mogelijke richtingen:

  • Tijdelijke piek: drukke marketingactie, bot-aanval, of een langzame query die alle connections vasthoudt — meestal lost dat zichzelf binnen minuten op
  • Connection leak: code die wel verbindt maar nooit netjes mysqli_close() aanroept — dan stapelen connections op, en moet je in de code kijken

Bij shared hosting: meld het bij je hoster, want zij beheren de max_connections instelling.

Warning: mysqli_connect(): Headers and client library minor version mismatch

Geen echte fout — een waarschuwing dat de PHP-mysqlnd-bibliotheek en de MySQL-server iets uit fase lopen qua versie. Functioneel werkt alles. Onderdrukken kan met:

// Helemaal aan het begin van het script, vóór mysqli_connect()
mysqli_report(MYSQLI_REPORT_OFF);

Maar de echte fix is: hoster vragen om mysqlnd te updaten, of een nieuwere PHP-versie te kiezen. Zie ook PHP-versie veilig upgraden.

Query-fouten — mysqli_query() en de gevolg-warnings

Als mysqli_query() faalt, geeft het functie false terug. Daarna probeert je code dat resultaat te gebruiken — en dan komen de bekende vervolgfouten. Dit is de tweede grote categorie. De foutmelding zelf zegt vaak meer dan je denkt.

Warning: mysqli_query() expects parameter 1 to be mysqli, bool given

(In PHP 8+: mysqli_query(): Argument #1 ($mysql) must be of type mysqli, bool given.)

De variabele die je doorgeeft als databaseverbinding is geen verbinding maar een boolean — typisch false. De verbinding is dus eerder al mislukt, maar de code is blind doorgegaan. Bovenin je script staat waarschijnlijk:

$conn = mysqli_connect($host, $user, $pass, $db);
// Geen check, dus als dit faalt is $conn nu false
$result = mysqli_query($conn, "SELECT ..."); // → deze warning

Fix: voeg een fatsoenlijke connection-check toe:

$conn = mysqli_connect($host, $user, $pass, $db);
if (!$conn) {
    error_log('DB connect failed: ' . mysqli_connect_error());
    die('Tijdelijk niet beschikbaar.');
}

Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, bool given

(En de varianten mysqli_fetch_array(), mysqli_fetch_row(), mysqli_fetch_object().)

De query zelf is mislukt — vaak een SQL-syntaxfout, een niet-bestaande tabel of kolom, of onvoldoende rechten. mysqli_query() gaf false terug, en je code probeert nu rijen te lezen uit dat false-resultaat.

Fix: vraag op waaróm de query faalde voor je doorgaat:

$result = mysqli_query($conn, "SELECT * FROM gebruikers WHERE id = $id");
if (!$result) {
    error_log('Query failed: ' . mysqli_error($conn));
    return [];
}
while ($row = mysqli_fetch_assoc($result)) { ... }

Echte oorzaken die ik in de praktijk vaak zie:

  • Tabelnaam is gewijzigd of staat in een andere case (Linux is hoofdlettergevoelig — Usersusers)
  • Migratie van MySQL 5.x → 8.x: gereserveerde keywords zoals rank, groups moeten in backticks
  • Encoding-mismatch: utf8 vs utf8mb4 waar emoji's of speciale tekens in zitten
  • Een eerdere query die niet was vrijgegeven, waardoor de connectie in een rare state staat

Warning: mysqli_num_rows() expects parameter 1 to be mysqli_result, bool given

Zelfde oorzaak als hierboven: de query faalde, je krijgt false terug, en je vraagt het aantal rijen op uit een bool. Fix: check eerst of $result waarheidsachtig is voor je mysqli_num_rows() aanroept.

Warning: mysqli_real_escape_string() expects parameter 1 to be mysqli, null given

De connectie-variabele is null — vaak omdat een functie wordt aangeroepen voordat de databaseverbinding is opgezet, of in een class waar $this->conn nooit is geïnitialiseerd. In oudere code zie je ook mysqli_real_escape_string() aanroepen zonder eerste argument (uit pre-PHP-7-tijdperk) — dat moet altijd met de actieve connectie als eerste parameter.

Warning: mysqli_select_db() expects parameter 1 to be mysqli, string given

Klassieke argument-volgorde-fout. In de oude mysql_*-API was de syntaxis mysql_select_db($dbname, $conn). In mysqli_* staan de argumenten omgedraaid: mysqli_select_db($conn, $dbname). Code die ooit van mysql_ naar mysqli_ is omgezet via een simpele search-and-replace heeft dit vaak fout staan.

PHP 8 specifiek: van Warning naar Fatal Error

Sinds PHP 8.0 is de mysqli-extensie standaard veel strenger. Wat in PHP 7 een Warning was die je site doorliet werken, is in PHP 8 vaak een mysqli_sql_exception die het script direct stopt.

Fatal error: Uncaught mysqli_sql_exception: ...

Dit is dezelfde fout als hierboven, maar nu fataal. Het scenario:

  • PHP-versie geüpgraded van 7.4 naar 8.x
  • Code zonder fatsoenlijke error handling
  • Eerste falende query → uncaught exception → witte pagina of 500-error

Twee aanpakken:

1. Snel terug naar het oude gedrag (alleen om tijd te kopen):

// Heel vroeg in je bootstrap, vóór mysqli_connect()
mysqli_report(MYSQLI_REPORT_OFF);

2. Goed: try/catch om databasecode:

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try {
    $conn = mysqli_connect($host, $user, $pass, $db);
    $result = mysqli_query($conn, $sql);
    // ...
} catch (mysqli_sql_exception $e) {
    error_log('DB-fout: ' . $e->getMessage());
    // toon nette foutpagina
}

Deprecated: mysqli_real_escape_string(): Passing null to parameter

Deze deprecation hoort bij PHP 8.1+. Code geeft null door waar een string wordt verwacht. Komt veel voor bij oude formulier-handlers die $_POST['veld'] doorgeven aan escape — als het veld leeg is, is het null in plaats van leeg-string. Fix:

$naam = mysqli_real_escape_string($conn, $_POST['naam'] ?? '');

De ouderwetse mysql_* fouten — geen mysqli, maar relevant

Bij iets oudere sites kom je nog mysql_*-functies (zónder de "i") tegen. Die zijn al verwijderd uit PHP 7.0. De errors:

Fatal error: Uncaught Error: Call to undefined function mysql_connect()

De code stamt uit het pre-PHP-7-tijdperk en draait nu op een nieuwere PHP-versie waar de mysql_*-familie weg is. Er is geen "snelle fix" — je moet de code migreren naar mysqli_* of PDO. Voor enkele scripts kan een vinden-en-vervangen werken; voor grotere sites is dit vakwerk omdat parameter-volgordes en error-handling veranderen.

Tijdelijke oplossing: PHP-versie terugzetten naar 5.6 (als je hoster dat nog ondersteunt — meestal niet meer). Echte oplossing: code moderniseren.

Sectie speciaal voor WordPress: "Error establishing a database connection"

WordPress vangt de meeste mysqli-fouten zelf op en toont z'n eigen melding: "Error establishing a database connection". De onderliggende mysqli-warning vind je in je error_log of in wp-content/debug.log als je WP_DEBUG aanzet:

// In wp-config.php
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

Veelvoorkomende WordPress-specifieke oorzaken:

  • Database-credentials in wp-config.php kloppen niet (zie boven bij Access denied)
  • wp-config.php heeft een UTF-8 BOM — onzichtbare bytes vooraan het bestand. Open in een editor als VS Code en sla op zonder BOM
  • Beschadigde database-tabellen — fix: voeg define('WP_ALLOW_REPAIR', true); toe en bezoek /wp-admin/maint/repair.php
  • Te veel WordPress-cron-jobs die parallel queries doen op een hoster met lage max_connections
  • Plugin (vooral cache- of search-plugins) doet directe DB-calls die de connection-pool vol trekken

Algemeen debugproces — als je de oorzaak echt niet vindt

  1. Foutmelding letterlijk lezen. PHP geeft vaak het bestand en regelnummer mee — daar moet je beginnen, niet bij de symptomen verderop in het log
  2. Test de databaseverbinding apart met een minimaal scriptje:
    <?php
    $conn = mysqli_connect('localhost', 'user', 'pass', 'dbname');
    if (!$conn) {
        die('Fail: ' . mysqli_connect_error());
    }
    echo 'OK';
    Werkt dit? Dan ligt 't aan je CMS-config. Niet? Dan aan hosting/credentials
  3. Check de hosting status-pagina en je error_log voordat je in de code duikt — soms is 't simpelweg een storing
  4. Check recente wijzigingen: PHP-versie geüpgraded? Plugin geüpdatet? Migratie geweest? In 80% van de gevallen is het laatste wijziging-moment de oorzaak
  5. phpMyAdmin opent normaal? Zo ja, dan werkt MySQL prima en zit het in PHP-code of credentials. Zo nee, dan is de databaseserver zelf het probleem
Belangrijk: verwijder na het debuggen alle phpinfo()-pagina's, debug-bestanden en display_errors = 1-instellingen. Een actieve display_errors op een productiesite lekt info naar bots en aanvallers. Zet WP_DEBUG_DISPLAY op false en log alleen naar bestand.

Wanneer schakel je hulp in?

  • De site geeft "Error establishing a database connection" en je weet niet of het hosting, credentials of database-corruption is
  • Sinds een PHP-upgrade naar 8.x staat alles vol mysqli_sql_exception-meldingen — iemand moet de code modern maken
  • Je code gebruikt nog mysql_* (zonder "i") en moet gemigreerd worden naar mysqli_* of PDO zonder dat de functionaliteit verandert
  • Intermittent "Too many connections" of "MySQL server has gone away" tijdens piekmomenten — vraagt om query-optimalisatie of connection-pooling
  • Custom code waarvan de oorspronkelijke ontwikkelaar niet meer beschikbaar is, en jij de SQL-fouten niet zelf wilt of kunt oplossen

Een mysqli-fout is in 90% van de gevallen niet zo dramatisch als 'ie eruit ziet — de databaseserver werkt nog, en het is meestal één foute regel of één instelling. Maar je site wel of niet zien werken hangt aan dat ene detail. Met de stappen hierboven vind je in de meeste gevallen binnen een halfuur de oorzaak. Lukt het niet — neem dan contact op, dit is dagelijks werk.