Error Message
ERROR 1267 (HY000): Illegal mix of collations (utf8mb4_unicode_ci,IMPLICIT) and (utf8mb4_general_ci,IMPLICIT) for operation '='The two collations and the operation change with the query. Common variations:
ERROR 1267 (HY000): Illegal mix of collations (utf8mb4_0900_ai_ci,IMPLICIT) and (utf8mb4_general_ci,IMPLICIT) for operation '='
ERROR 1267 (HY000): Illegal mix of collations for operation 'UNION'
ERROR 1271 (HY000): Illegal mix of collations for operation 'concat'If you see 1271 instead of 1267, it’s the same collation-mismatch problem, just raised by a function/expression (such as CONCAT) rather than a direct comparison. Treat them together.
What Triggers This Error
MySQL was asked to compare or combine two strings whose collations are incompatible, and it cannot decide which one wins. Almost every time, this traces back to a charset migration that converted some objects and missed others. The error message names both collations, which is the fastest clue to where the mismatch lives:
JOINacross columns with different collations:utf8mb4_general_cion one table,utf8mb4_unicode_cion the other.- Column compared to a literal: the column's collation differs from
collation_connection, and the literal takes the connection's. UNIONof mismatched columns: the two branches resolve to different collations.- MySQL 8 default against legacy tables: new tables get
utf8mb4_0900_ai_ci, while anything restored from a 5.7 dump keepsutf8mb4_general_ci. - Stored routine parameter mismatch: a parameter's collation differs from the column it is compared against inside the routine.
Fix by Scenario
JOIN across columns with different collations
This is the one you will hit most. Two tables were created months apart with different defaults, and a join on their text keys blows up.
SELECT u.name, o.id
FROM users u
JOIN orders o ON u.email = o.email;
-- ERROR 1267: Illegal mix of collations ... for operation '='Confirm the mismatch first:
SELECT TABLE_NAME, COLUMN_NAME, COLLATION_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'mydb'
AND COLUMN_NAME = 'email'
AND TABLE_NAME IN ('users', 'orders');For a one-off query, force a collation on the comparison:
SELECT u.name, o.id
FROM users u
JOIN orders o
ON u.email = o.email COLLATE utf8mb4_unicode_ci;That gets you unblocked, but it is a patch. If you find yourself adding COLLATE to query after query, the columns themselves disagree and you should fix them once (see Prevention) rather than annotating every join forever.
Column compared to a literal
A plain WHERE col = 'value' can fail when the column's collation differs from collation_connection. The literal inherits the connection collation, the column has its own, and MySQL refuses to guess.
SHOW VARIABLES LIKE 'collation_connection';
-- e.g. utf8mb4_0900_ai_ci, while the column is utf8mb4_general_ciEither align the session with the column:
SET collation_connection = 'utf8mb4_general_ci';Or pin the literal's collation in the predicate:
SELECT * FROM users WHERE name = 'José' COLLATE utf8mb4_general_ci;UNION of mismatched columns
When two SELECT branches return text with different collations, the UNION cannot pick one. Normalize both sides with CONVERT():
SELECT CONVERT(email USING utf8mb4) COLLATE utf8mb4_unicode_ci FROM users
UNION
SELECT CONVERT(email USING utf8mb4) COLLATE utf8mb4_unicode_ci FROM legacy_users;MySQL 8 default against legacy tables
MySQL 8.0 and later default new tables to utf8mb4_0900_ai_ci. Tables restored from a 5.7 dump keep utf8mb4_general_ci. Any comparison across that line fires 1267. Pick one target collation for the whole schema and convert the stragglers to it:
ALTER TABLE legacy_users
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;Convert consistently. A schema with _general_ci, _unicode_ci, and _0900_ai_ci scattered across tables will keep producing this error until you settle on one.
Stored routine parameter mismatch
A procedure parameter declared without an explicit collation takes the database default, which may not match the column it touches.
CREATE PROCEDURE find_user(IN p_email VARCHAR(255))
BEGIN
SELECT * FROM users WHERE email = p_email COLLATE utf8mb4_unicode_ci;
END;Pin the collation in the comparison, or declare the parameter with the matching CHARACTER SET and COLLATE.
Prevention
- Standardize on one charset and one collation across server, database, table, and column. As of MySQL 8.4,
utf8mb4with a single collation is the right default:utf8mb4_0900_ai_cifor a fresh deployment, orutf8mb4_unicode_ciif you are matching an existing fleet. - After a 5.7 to 8.0 upgrade or a restore, audit for drift before it bites:
SELECT DISTINCT TABLE_NAME, COLLATION_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'mydb' AND DATA_TYPE IN ('varchar','char','text')
ORDER BY COLLATION_NAME;- Set the connection collation in every application connection string, with
SET NAMES 'utf8mb4' COLLATE 'utf8mb4_0900_ai_ci', so literals match your columns. - If you genuinely need two collations in one schema, expect to write explicit
COLLATEclauses on every cross-collation comparison. Coercion will not save you.
Bytebase's SQL Review can require a consistent charset and collation on all new tables and columns, stopping the drift that causes 1267 before it reaches production. See also ERROR 1366: Incorrect String Value and ERROR 1071: Specified Key Was Too Long for the related charset traps.