Kaum eine dynamische PHP-Anwendung kommt ohne Datenbank aus, und alles beginnt mit einem sauberen Verbindungsaufbau. Wer hier schlampt, riskiert stumme Fehler oder offene Sicherheitslücken. Dieses Tutorial vergleicht die beiden etablierten Wege, die PHP dafür mitbringt, und zeigt, wann welcher die bessere Wahl ist.
Zwei Wege zur PHP Datenbankverbindung
In jedem ernsthaften PHP-Projekt taucht früh die gleiche Frage auf: Wie baut man eine zuverlässige Verbindung zur Datenbank auf, ohne Sicherheitsfehler zu riskieren? PHP bietet dafür zwei eingebaute Wege. PDO (PHP Data Objects) ist eine Abstraktionsschicht, die mehrere Datenbanken unter einer einheitlichen API bedient. mysqli ist eine speziell auf MySQL und MariaDB zugeschnittene Erweiterung, die einige eigene Features mitbringt. Wichtig ist in beiden Fällen, dass Benutzername und Kennwort nirgendwo offen im Code liegen. Wer Hostnamen, Datenbankname und Charset sauber angibt und die ersten Statements absetzen kann, hat das Fundament jeder PHP-Anwendung gelegt.

Bevor DSN, Fehler-Modus und Persistent Connections im Detail folgen, lohnt sich ein kurzer Blick auf die Gemeinsamkeiten, die beide Wege heute teilen.
Beide Erweiterungen erlauben sichere Prepared Statements, beide werfen bei sauberer Konfiguration Exceptions im Fehlerfall, und beide sind in modernen PHP-Versionen aktiv gepflegt. Der Unterschied liegt im Detail: in der Wechselbarkeit zwischen Datenbanken, in der API-Konsistenz und in den verfügbaren Sonderfunktionen. Dieses Tutorial zeigt Schritt für Schritt, wie eine PHP Datenbank Verbindung mit beiden Wegen aussieht und wann welche Wahl sinnvoll ist.
Erste Verbindung lokal mit XAMPP
Für die ersten Schritte ist eine lokale Umgebung mit XAMPP der pragmatische Weg. Nach der Installation läuft MySQL/MariaDB unter localhost auf dem Standard-Port 3306, ein User root ohne Passwort ist vorhanden. Eine Datenbank wird zuerst in phpMyAdmin (http://localhost/phpmyadmin) angelegt: links auf "Neu", einen Namen wie shop wählen, Kollation utf8mb4_unicode_ci. Eine Beispiel-Tabelle produkt mit zwei Spalten reicht für das erste Lesen völlig aus.
<?php
/* Erste Verbindung lokal: XAMPP, root ohne Passwort */
$pdo = new PDO('mysql:host=localhost;dbname=shop;charset=utf8mb4', 'root', '', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$stmt = $pdo->query('SELECT id, name FROM produkt');
foreach ($stmt as $zeile) {
echo $zeile['id'] . ': ' . $zeile['name'] . PHP_EOL;
}
Damit Fehler beim Entwickeln auch wirklich sichtbar werden, lohnt sich während der Lernphase ein kurzer Block in der php.ini oder am Anfang des Skripts. error_reporting(E_ALL); und ini_set('display_errors', '1'); machen jeden Tippfehler sofort lesbar. Für Production gilt das Gegenteil: dort werden Fehler ins Log umgeleitet, nicht an den Browser.
PDO Connect mit DSN und Fehler-Modus
Eine PDO-Variante der PHP Datenbank Verbindung wird über einen DSN (Data Source Name) als Parameter konfiguriert. Der String enthält Treiber, Host, den Namen der Datenbank und das Charset. Im Konstruktor-Aufruf werden zusätzlich Benutzername, Kennwort und Optionen übergeben. Wer lokal mit XAMPP arbeitet, nutzt häufig den User root ohne Passwort und legt die Tabelle vorher in phpMyAdmin an. Sehr wichtig ist der Exception-Modus, sonst bleiben Fehlermeldungen stumm und das Skript versucht stündlich Queries auszuführen, ohne dass jemand die Fehlermeldung sieht.
<?php
$dsn = 'mysql:host=localhost;dbname=shop;charset=utf8mb4';
$user = 'app_user';
$pass = 'geheim';
try {
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
} catch (PDOException $e) {
error_log($e->getMessage());
exit('Datenbank nicht erreichbar.');
}
Die Option ATTR_EMULATE_PREPARES = false ist eine kleine, aber wichtige Schraube: sie sorgt dafür, dass echte Prepared Statements an die Datenbank gehen, statt clientseitig nachgebildet zu werden. Damit greifen die Sicherheitsgarantien zuverlässig. Mehr über Prepared Statements selbst zeigt das Tutorial PHP PDO und Prepared Statements.
mysqli Connect mit Report-Modus
Die mysqli-Variante der PHP Datenbank Verbindung kennt einen ähnlichen Mechanismus, nutzt aber eine globale Funktion. mysqli_report() schaltet die Fehlerausgabe aus stillem Schweigen auf Exceptions um. Ohne diese Zeile bleibt ein fehlgeschlagener Connect oft unbemerkt.
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try {
$mysqli = new mysqli('localhost', 'app_user', 'geheim', 'shop');
$mysqli->set_charset('utf8mb4');
} catch (mysqli_sql_exception $e) {
error_log($e->getMessage());
exit('Datenbank nicht erreichbar.');
}
Auffällig ist, dass das Charset bei mysqli über eine separate Methode gesetzt wird. Bei PDO dagegen ist es Teil des DSN. In beiden Fällen sollte der Wert utf8mb4 lauten, damit auch Emojis und 4-Byte-Unicode-Zeichen korrekt gespeichert werden. Eine PHP Datenbank Verbindung ohne korrektes Charset zählt zu den häufigsten Frust-Quellen.
Zugangsdaten sauber auslagern
Eine PHP Datenbank Verbindung mit hartkodierten Zugangsdaten ist ein klassisches Anti-Pattern. Sobald der Code in ein Repository wandert, wandern Passwörter mit. Besser ist eine separate Konfigurationsdatei in einem geschützten Verzeichnis, die über .gitignore ausgeschlossen wird und nur auf dem jeweiligen Server liegt. Das Skript sollte die Werte ausschließlich intern verwenden und sie niemals per echo an den Browser ausgeben.
<?php
/* db-config.php (gitignored) */
return [
'host' => 'localhost',
'dbname' => 'shop',
'user' => 'app_user',
'pass' => 'geheim',
'charset' => 'utf8mb4',
];
<?php
$cfg = require __DIR__ . '/db-config.php';
$dsn = "mysql:host={$cfg['host']};dbname={$cfg['dbname']};charset={$cfg['charset']}";
$pdo = new PDO($dsn, $cfg['user'], $cfg['pass'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
Eine andere verbreitete Variante ist eine .env-Datei plus eine kleine Loader-Bibliothek. Wer mit reinem PHP arbeitet, kann Zugangsdaten auch über Umgebungsvariablen lesen. Mehr dazu im Tutorial getenv() und putenv().
Charset richtig setzen (utf8mb4)
Ein vergessenes oder falsches Charset zählt zu den häufigsten Frust-Quellen. Sobald Umlaute oder Emojis ins Spiel kommen, werden sie als Fragezeichen oder als seltsame Zeichenketten gespeichert. Bei PDO gehört charset=utf8mb4 direkt in den DSN, bei mysqli wird set_charset('utf8mb4') direkt nach dem Verbindungsaufbau aufgerufen.
<?php
/* PDO: Charset im DSN */
$pdo = new PDO('mysql:host=localhost;dbname=shop;charset=utf8mb4', $user, $pass);
/* mysqli: Charset nach Connect */
$mysqli = new mysqli('localhost', $user, $pass, 'shop');
$mysqli->set_charset('utf8mb4');
Wichtig: utf8 (alt) ist in MySQL nur 3 Byte breit und kann keine Emojis speichern. Heutige Projekte sollten konsequent auf utf8mb4 setzen, sowohl in der DB-Konfiguration als auch in der PHP Datenbank Verbindung.
Persistent Connections, Pros und Cons
Persistent Connections bleiben über den Request hinaus offen und werden vom nächsten Request wiederverwendet. Das spart die Latenz für den TCP-Handshake und die Authentifizierung. In PDO wird das über die Option ATTR_PERSISTENT aktiviert.
<?php
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
/* nur einsetzen, wenn der Server-Setup das wirklich rechtfertigt */
Der Pferdefuß: Persistent Connections vererben Status. Eine offene Transaktion vom Vor-Request kann den nächsten blockieren, ein verändertes Charset bleibt erhalten, gesetzte Session-Variablen wirken weiter. Das macht das Debugging knifflig. Persistent Connections sind sinnvoll bei klassischen mod_php-Setups mit hoher Last und kurzem Request, sie sind oft schädlich in PHP-FPM-Worker-Konfigurationen, in denen Worker ohnehin länger leben.
Entscheidungsmatrix PDO vs. mysqli
Welche Erweiterung passt nun zu welchem Projekt? Die folgende Tabelle fasst die wichtigsten Kriterien zusammen. Wichtig ist, bei beiden Wegen den Charset und den Connection-Mode konsequent anzugeben, sonst sind spätere Queries nicht zuverlässig auszuführen. Die Angabe des Charsets entscheidet zudem darüber, ob Umlaute korrekt gespeichert werden.
| Kriterium | PDO | mysqli |
| Multi-DB-Fähig | Ja, viele Treiber | Nein, nur MySQL/MariaDB |
| Benannte Platzhalter | Ja (:name) | Nein, nur ? |
| API-Konsistenz | hoch, einheitlich | gemischt prozedural/OOP |
| Spezial-Features wie multi_query | nein | ja |
| Default in Frameworks | meist PDO | seltener |
| Einarbeitungsaufwand | niedrig | etwas höher |
Pragmatisch heißt das: Wer flexibel zwischen MySQL, PostgreSQL oder SQLite wechseln möchte oder sich an Frameworks orientiert, ist mit PDO besser beraten. Wer bewusst MySQL-Spezifika nutzt, etwa multi_query oder asynchrone Abfragen, kann mit mysqli mehr aus der Engine herausholen. Für reine CRUD-Anwendungen sind beide Wege gleich gut.
Stolperfallen und Verbindungs-Lecks
Egal ob PDO oder mysqli: ein paar Fehlerquellen tauchen immer wieder auf. Die wichtigste ist eine fehlende oder falsche Fehlerbehandlung beim Connect, weil sie zu weissen Seiten ohne Aussage führt. Ebenfalls beliebt sind Verbindungs-Lecks: in langen Worker-Prozessen oder CLI-Skripten werden Verbindungen geöffnet, aber nie sauber freigegeben.
<?php
/* explizit schliessen, vor allem in CLI-Skripten und langen Worker-Prozessen */
$pdo = null;
$mysqli->close();
Ein weiterer Klassiker ist Lazy-Connect: die Verbindung wird erst dann aufgebaut, wenn sie wirklich benötigt wird, nicht im Bootstrap. Damit vermeidet man unnötige DB-Verbindungen für Cache-Hits oder statische Routen. Wer noch tiefer in die Sicherheit der Anwendung einsteigen will, findet im Tutorial zu PHP password_hash das passende Pendant für die Login-Prüfung gegen die Datenbank.
flowchart TD
A[PHP-Anwendung] --> B{PDO oder mysqli?}
B -->|Multi-DB / einheitliche API| C[PDO]
B -->|nur MySQL oder spezielle Features| D[mysqli]
C --> E[Verbindung zu DB]
D --> E
E --> F[Queries ausfuehren]
Fazit zur PHP Datenbank Verbindung
Eine sichere PHP Datenbank Verbindung beginnt mit drei Punkten: aktiver Fehler-Modus, korrektes Charset und ausgelagerte Zugangsdaten. Ob die Wahl auf PDO oder mysqli fällt, hängt vom Projekt ab. Für reine MySQL-Setups sind beide solide, für Mehr-Datenbank-Architekturen oder framework-orientierte Projekte ist PDO die natürliche Wahl. Persistent Connections können Performance bringen, sollten aber bewusst eingesetzt werden, weil sie versteckten Status mitschleppen. Wer die hier gezeigten Patterns konsequent anwendet, hat eine PHP Datenbank Verbindung, die sich auch unter Last stabil und nachvollziehbar verhält.