I've seen this a hundred times. You run a query and your data comes back as ééé or ????? or weird symbols. It's frustrating. But the fix is simple — you don't need to re-import your database.
The Fix: Match Your Connection Charset to Your Table
Most of the time, your table uses one charset and your connection uses another. PHP's default connection charset is often latin1. If your table stores utf8mb4 (which it should for emojis and good Unicode support), you get garbled output.
- Check your table charset — run this SQL in phpMyAdmin or command line:
Look forSHOW CREATE TABLE your_table_name;DEFAULT CHARSET=utf8mb4orlatin1. Write it down. - Set your PHP connection charset — right after you connect, add this line:
If you use PDO, do this:mysqli_set_charset($connection, "utf8mb4");
Replace$pdo = new PDO($dsn, $user, $pass, [ PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4" ]);utf8mb4with whatever charset your table uses. For latin1 tables, uselatin1. - Test it — refresh your page. If the text looks normal, you're done.
After you run mysqli_set_charset(), the connection now tells MySQL "hey, I speak utf8mb4". MySQL then sends data already encoded in that charset. No more garbled text.
Why This Happens
MySQL has three layers of encoding: the table's default charset, the connection charset, and the client's charset. If any two don't match, MySQL tries to convert between them. That conversion is where the garbage appears.
Real-world scenario: You import a CSV file saved as UTF-8. The table gets created with utf8mb4_general_ci. But PHP's default connection charset is latin1_swedish_ci (the MySQL default). When you SELECT data, MySQL thinks your client expects latin1, so it converts the utf8mb4 bytes to latin1. That's when é becomes é.
The real fix is to set the connection charset explicitly. Skip the SET NAMES hack — use mysqli_set_charset() because it also sets the client encoding on the PHP side.
Less Common Variations
Tables with mixed charsets
If you have a table with some columns in utf8mb4 and others in latin1, you'll get garbled text only for certain columns. Check the column charset with:
SHOW FULL COLUMNS FROM your_table_name;
Fix: Convert all columns to the same charset:
ALTER TABLE your_table_name MODIFY your_column_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Old data stored in wrong charset
Sometimes the data itself is corrupted. For example, someone inserted double-encoded UTF-8. You see é instead of é. That's harder to fix. One approach: export the table as a text file, open it in a hex editor, and manually clean the bytes. Or use the CONVERT() function:
UPDATE your_table SET your_column = CONVERT(CONVERT(your_column USING latin1) USING utf8mb4);
This assumes the data was originally UTF-8 but stored as latin1. Test on a backup first.
Command line client
If you use mysql command line and see garbled text, your terminal charset doesn't match. Set it with:
mysql --default-character-set=utf8mb4 -u username -p
Prevention for Future
Do these three things from day one and you'll never see garbled text again:
- Set your connection charset in every script — right after
mysqli_connect()or PDO constructor. No exceptions. - Use UTF-8 everywhere — your database default, your table default, your column charset, your HTML page
<meta charset="UTF-8">. Everything. Only use latin1 if you have legacy data that truly needs it (like an old postal code table). - When creating new tables, explicitly set the charset — don't rely on defaults. Example:
CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) ) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - If you import data, specify the file charset — in phpMyAdmin, choose UTF-8 from the dropdown. Or use
mysqlimport --default-character-set=utf8mb4.
One last thing: don't use utf8 charset. Use utf8mb4. MySQL's utf8 is broken — it only supports up to 3-byte characters, so emojis and some Chinese characters get truncated. utf8mb4 is the real UTF-8.