MySQL Zeichensatz und Umlaute — Probleme lösen
Aus „Ü“ wird „ü“, aus „ß“ wird „ß“, und dein schön geschriebener Text sieht aus wie ein Kryptogramm. Zeichensatz-Probleme in MySQL gehören zu den nervigsten Fehlern überhaupt — weil sie oft erst spät auffallen und die Ursache schwer zu finden ist. Hier erkläre ich dir, warum das passiert und wie du es ein für alle Mal löst.
Warum gibt es überhaupt Encoding-Probleme?
Zwischen deiner Anwendung und den Daten in der Datenbank gibt es mehrere Stellen, an denen der Zeichensatz eine Rolle spielt:
- Die Datenbank — hat einen Default-Zeichensatz
- Die Tabelle — kann einen eigenen Zeichensatz haben
- Die Spalte — kann nochmal abweichen
- Die Verbindung — zwischen Client und Server
- Die Anwendung — PHP, Python, etc.
- Die HTML-Seite — Meta-Charset im Header
Wenn an irgendeiner dieser Stellen ein anderer Zeichensatz verwendet wird, geht’s schief. Der häufigste Fall: Die Datenbank speichert in latin1, aber die Anwendung sendet utf8 — oder umgekehrt.
utf8 vs. utf8mb4 — was ist der Unterschied?
Das ist eine MySQL-Eigenheit, die schon viele Leute verwirrt hat:
- utf8 in MySQL ist nicht echtes UTF-8. Es unterstützt nur Zeichen mit maximal 3 Bytes — also kein Emoji, kein CJK-Supplement, keine seltenen Unicode-Zeichen. Dieses Verhalten unterscheidet sich je nach MySQL-Version.
- utf8mb4 ist das echte UTF-8. Es unterstützt alle Unicode-Zeichen, einschließlich Emojis (4 Bytes).
Empfehlung: Nutze immer utf8mb4. Seit MySQL 8.0 ist es der Standard, bei älteren Versionen musst du es explizit setzen.
| Zeichensatz | Max. Bytes | Emojis | Empfohlen |
|---|---|---|---|
latin1 |
1 | Nein | Nein |
utf8 (MySQL) |
3 | Nein | Nein |
utf8mb4 |
4 | Ja | Ja |
Aktuellen Zeichensatz prüfen
Server-Einstellungen
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
Ausgabe sieht dann etwa so aus:
+--------------------------+-------------------+
| Variable_name | Value |
+--------------------------+-------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
+--------------------------+-------------------+
Im Idealfall steht überall utf8mb4. Wenn da latin1 auftaucht, hast du dein Problem gefunden.
Datenbank-Zeichensatz
SELECT default_character_set_name, default_collation_name
FROM information_schema.schemata
WHERE schema_name = 'meine_datenbank';
Tabellen-Zeichensatz
SELECT table_name, table_collation
FROM information_schema.tables
WHERE table_schema = 'meine_datenbank';
Spalten-Zeichensatz
SELECT column_name, character_set_name, collation_name
FROM information_schema.columns
WHERE table_schema = 'meine_datenbank'
AND table_name = 'users';
Zeichensatz korrigieren — Schritt für Schritt
Wichtig: Mach vorher ein Backup! Zeichensatz-Konvertierungen können bei falsch kodierten Daten zu Datenverlust führen.
1. Server-Default setzen
In der my.cnf / my.ini:
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
Danach MySQL neu starten.
2. Datenbank konvertieren
ALTER DATABASE meine_datenbank
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
3. Alle Tabellen konvertieren
Einzelne Tabelle:
ALTER TABLE users
CONVERT TO CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
Alle Tabellen auf einmal — mit einem generierten SQL-Statement:
SELECT CONCAT('ALTER TABLE `', table_name, '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;')
FROM information_schema.tables
WHERE table_schema = 'meine_datenbank'
AND table_type = 'BASE TABLE';
Die Ausgabe kopieren und ausführen.
4. Verbindung in der Anwendung setzen
PHP (PDO):
$pdo = new PDO(
'mysql:host=localhost;dbname=meine_datenbank;charset=utf8mb4',
'user',
'passwort'
);
PHP (mysqli):
$mysqli = new mysqli('localhost', 'user', 'passwort', 'meine_datenbank');
$mysqli->set_charset('utf8mb4');
PHP (veraltet, mysql_*):
mysql_set_charset('utf8mb4');
// Oder:
mysql_query("SET NAMES 'utf8mb4'");
WordPress (wp-config.php):
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', 'utf8mb4_unicode_ci');
Das „Doppelt-kodiert“-Problem
Das fieseste Problem: Daten wurden als UTF-8 in eine latin1-Spalte geschrieben. MySQL hat die UTF-8-Bytes als latin1 interpretiert und gespeichert. Wenn du jetzt die Spalte auf utf8mb4 konvertierst, wird alles nochmal kodiert — und du hast doppelt kodierten Müll.
Erkennen
Wenn „Ü“ als „ü“ in der Datenbank steht (2 Zeichen statt 1), sind die Daten doppelt kodiert.
Lösung
Der Trick: Konvertiere erst zu latin1 (Binary), dann zu utf8mb4:
ALTER TABLE users
MODIFY name VARCHAR(255)
CHARACTER SET latin1;
ALTER TABLE users
MODIFY name VARBINARY(255);
ALTER TABLE users
MODIFY name VARCHAR(255)
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
Das funktioniert, weil der Zwischenschritt über VARBINARY die Bytes unverändert lässt.
Collation — was ist das?
Die Collation bestimmt, wie Zeichen verglichen und sortiert werden. Für deutsch ist das wichtig wegen Umlauten:
| Collation | Verhalten | Empfehlung |
|---|---|---|
utf8mb4_general_ci |
Schnell, aber ungenau bei Sonderzeichen | Okay für einfache Anwendungen |
utf8mb4_unicode_ci |
Korrekte Unicode-Sortierung | Gute Wahl |
utf8mb4_german2_ci |
Deutsche Telefonbuch-Sortierung (ä=ae) | Wenn du deutsche Sortierung brauchst |
utf8mb4_0900_ai_ci |
Neueste Unicode-Sortierung (MySQL 8.0+) | Beste Wahl ab MySQL 8.0 |
ci steht für „case insensitive“ — Groß- und Kleinschreibung wird bei Vergleichen ignoriert. cs wäre „case sensitive“.
Zeichensatz beim Dump/Import
Auch beim Backup und Restore muss der Zeichensatz stimmen:
# Export mit explizitem Charset (mehr Optionen im mysqldump-Tutorial)
mysqldump --default-character-set=utf8mb4 -u root -p meine_datenbank > backup.sql
# Import mit explizitem Charset
mysql --default-character-set=utf8mb4 -u root -p meine_datenbank < backup.sql
Prüfe auch den Anfang deiner Dump-Datei. Dort sollte stehen:
/*!40101 SET NAMES utf8mb4 */;
Wenn da SET NAMES latin1 steht, hast du den Dump mit dem falschen Zeichensatz erstellt.
Checkliste: Zeichensatz überall richtig setzen
- MySQL Server-Default:
utf8mb4inmy.cnf - Datenbank:
ALTER DATABASE ... CHARACTER SET utf8mb4 - Tabellen:
ALTER TABLE ... CONVERT TO CHARACTER SET utf8mb4 - Verbindung:
SET NAMES utf8mb4odercharset=utf8mb4im DSN - PHP-Anwendung:
set_charset('utf8mb4') - HTML:
<meta charset="utf-8"> - Dump/Import:
--default-character-set=utf8mb4
Wenn du alle sieben Punkte abgehakt hast, sind Umlaut-Probleme Geschichte. Der häufigste Fehler ist, nur an einer oder zwei Stellen utf8mb4 zu setzen und den Rest zu vergessen. Es müssen alle Glieder der Kette stimmen.