If emojis entered by your users are showing up as question marks in your database, the problem is almost certainly not your frontend. The input is correct. The font is fine. The issue is the MySQL character set.
This is exactly what happened while building posilog.com, a journaling app where users can write freely using any characters they want. Everything worked locally. Once deployed, any emoji in user input was silently replaced with
?.After ruling out a font issue, a missing
charsetmeta tag, and a frontend encoding problem, the diagnosis came down to one thing: MySQL's defaultutf8character set does not actually support emojis.
Why utf8 in MySQL Does Not Support Emojis
MySQL's utf8 encoding predates the emoji era. It only stores characters that require up to 3 bytes, but emojis fall under the Supplementary Multilingual Plane (SMP) of Unicode and require 4 bytes per character.
The result is that MySQL quietly drops any 4-byte character rather than raizing an error. Your app sends π, the database stores ?, and users never know their input was truncated.
To confirm what your server is currently using, run:
SELECT @@character_set_server, @@collation_server;
If the output shows utf8 and utf8_unicode_ci, the fix below applies to you.
Setting | Problem value | Correct value |
|---|---|---|
|
|
|
|
|
|
The Fix: Switch to utf8mb4
utf8mb4 is MySQL's full Unicode implementation. The mb4 stands for "multi-byte 4", meaning it supports the complete Unicode range including all emoji characters. Switching to it requires three updates: the server config, the database and tables, and the application connection.
Step 1: Update the MySQL Server Configuration
Open your MySQL config file (my.cnf on Linux, my.ini on Windows) and update the character set settings:
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
Then restart MySQL:
sudo systemctl restart mysql
Step 2: Update the Database and Tables
Changing the server config only affects new databases going forward. Existing databases and tables need to be converted:
ALTER DATABASE your_database_name
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
ALTER TABLE your_table_name
CONVERT TO CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
Run the ALTER TABLE command for each table that stores user-generated content.
Step 3: Update the Application Connection
The server and database can be fully configured for utf8mb4, but if the application connects using utf8, emojis will still be corrupted in transit. Set the charset explicitly in your connection:
PHP (PDO):
$pdo = new PDO(
'mysql:host=localhost;dbname=your_db;charset=utf8mb4',
'user',
'password'
);
Node.js (Sequelize):
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'mysql',
charset: 'utf8mb4',
collate: 'utf8mb4_unicode_ci'
});
Raw connection string:
mysql://user:pass@localhost:3306/dbname?charset=utf8mb4
Workarounds for Shared Hosting
Some shared hosting environments lock down MySQL server settings and do not allow you to change the character set at the server level. If that applies to you, there are two practical alternatives.
Move to a managed database. Providers like AWS RDS, Google Cloud SQL, and DigitalOcean Managed Databases give you full control over character set configuration. If emoji support is important to your users, this is the cleanest long-term option.
Encode emojis before storing. Convert emoji characters to Unicode escape sequences before writing to the database, then decode them when reading back. This avoids the 4-byte problem entirely at the cost of slightly more complex read and write logic.
Base64 encoding is a more blunt version of the same approach:
// Encode before storing
Buffer.from("Hello π", "utf8").toString("base64");
// Decode on retrieval
Buffer.from(encodedText, "base64").toString("utf8");
Worth noting: Base64 encoding increases storage size by roughly 33% and makes SQL searches against the column unreliable, so it is best used only when other options are unavailable.
Key Takeaways
MySQL's
utf8charset only supports 3-byte characters and silently drops emojis rather than throwing an error.utf8mb4is the correct charset for any application that handles user-generated text.The fix requires updates in three places: server config, database and table definitions, and the application connection string.
On shared hosting, encoding workarounds or a managed database are the practical alternatives.
Conclusion
Question marks where emojis should be is a data integrity problem, not a cosmetic one. User input is being silently truncated, which means the stored content does not match what the user submitted.
Switching to utf8mb4 fixes it completely. The change is small and the steps are straightforward, but it needs to be applied consistently across the server, the database, and the connection layer to take full effect.
Hit an edge case with a specific ORM or hosting provider? Describe it in the comments with the relevant config and error output.




