データベース

MySQL「Unknown collation: utf8mb4_0900_ai_ci」の直し方|DDL修正と移行後の確認

utf8mb4_0900_ai_ciでダンプのインポートが止まるときの確認手順。移行先の対応を調べ、データを変えずにDDLを修正し、末尾空白による一意制約の衝突まで検証します。MariaDBの対応版での違いも紹介。

この記事の目次
  1. 最初に、インポート先が0900を受け付けるか確認する
  2. MariaDBは「すべて未対応」ではない
  3. 変更するのはDDLの指定。INSERT内の文字列はそのまま残す
  4. mysqldumpの–default-character-setではDDLの照合順序を変えられない
  5. 1273が消えても、次に一意制約で止まることがある
  6. 検証用DBで確認した結果と、実データで見る項目
  7. 対応名の確認から、比較結果の確認までで直す

MySQLのダンプを別のサーバーへ入れたところ、Unknown collation: 'utf8mb4_0900_ai_ci'で止まった。このエラーは、実行先のサーバーがその照合順序名を受け付けないことを示します。

先に移行先でSHOW COLLATIONを実行し、未対応なら、対応する環境を用意するか、比較ルールの変更を検証したうえでDDLのCOLLATE指定を直します。 utf8mb4をutf8へ落としたり、ダンプ全体を文字列置換したりする前に、定義とデータを分けて確認してください。

最初に、インポート先が0900を受け付けるか確認する

インポートで使う接続先・ユーザーで、次のSQLを実行します。VERSIONとversion_commentは製品・版、DATABASE()は選択中のDBの確認です。DBをまだ選んでいなければDATABASE()はNULLになります。

SELECT VERSION(), @@version_comment, DATABASE();
SHOW COLLATION WHERE Collation = 'utf8mb4_0900_ai_ci';
SHOW COLLATION WHERE Collation = 'utf8mb4_unicode_ci';

最初のSHOW COLLATIONが0行なら、その接続先には指定した名前がありません。1行返るのにインポートで同じエラーが出るなら、GUIとコマンドで接続するホスト・ポート・サーバーが一致しているか、エラーに出た名前が本当に同じかを確認します。

移行先の状態 次にすること
0900が未対応。比較ルールを保ちたい 元と互換性のある環境への移行を検討する
0900が未対応。移行先の制約で照合順序を変える 候補の対応確認、DDL修正、比較と一意制約の検証へ進む
0900が対応済み 一律置換せず、実際のエラー箇所と製品間の意味の違いを調べる

MariaDBは「すべて未対応」ではない

MariaDBには、MySQLの0900名をUCA 1400系の照合順序への別名として受け付ける実装があります。対応課題MDEV-35256の修正版は11.4.5です。対応照合順序一覧でも、utf8mb4_0900_ai_ciはutf8mb4_uca1400_nopad_ai_ciの別名とされています。

名前が通ることとMySQLと完全に同じ比較になることは別です。製品名だけで置換の要否を決めず、使う版の対応と実データの検索結果を確かめます。

スポンサーリンク

変更するのはDDLの指定。INSERT内の文字列はそのまま残す

元のダンプを保管し、作業用コピーを用意します。エラーに表示された行の前後を開き、CREATE DATABASE・CREATE TABLE・列定義などのCOLLATE指定を確認してください。SQL本文、コメント、文字列リテラルに同じ単語がある場合もあるため、検索結果をすべて置換してはいけません。

以下は検証用の小さな表です。新しく用意した空のテストDBで扱います。

CREATE TABLE import_probe (
  id INT NOT NULL PRIMARY KEY,
  code VARCHAR(30) NOT NULL,
  note VARCHAR(100) NOT NULL,
  UNIQUE KEY uq_code (code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

移行先がutf8mb4_unicode_ciを受け付け、比較の変更を採用できると判断した場合の修正例です。末尾のCOLLATE指定だけを変更しています。utf8mb4は維持します。

CREATE TABLE import_probe (
  id INT NOT NULL PRIMARY KEY,
  code VARCHAR(30) NOT NULL,
  note VARCHAR(100) NOT NULL,
  UNIQUE KEY uq_code (code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

実際のダンプでは、テーブルの既定値だけでなく各列のCOLLATE、ビューや保存プログラム内の式にも指定があり得ます。定義を1つずつレビューし、変更差分が意図した指定だけか確認します。定義だけを再取得する方法を使う場合でも、DDL内のコメントやDEFAULTの文字列を巻き込まないようにします。

次は同じ表へ入れるデータです。noteに照合順序名と同じ文字列がありますが、これは保存したい値なので変更しません。

INSERT INTO import_probe (id, code, note) VALUES
  (1, 'alpha', 'utf8mb4_0900_ai_ci'),
  (2, 'alpha ', '末尾に空白あり');

ダンプ全体へ単純なsed置換をかけると、1行目のnoteまで変わります。CMS本文や設定値の中に同じ単語がある場合も同様です。SQLとしての指定を修正する作業と、保存データを書き換える作業を混ぜないことが大切です。

mysqldumpの–default-character-setではDDLの照合順序を変えられない

--default-character-set=utf8mb4は文字セットの指定です。既存テーブルのCOLLATE=utf8mb4_0900_ai_ciをutf8mb4_unicode_ciへ変換するオプションではありません。mysqldumpの公式説明でも、文字セットとSET NAMESの出力に関する設定として扱われています。

また、移行先DBの既定照合順序を変更しても、ダンプのCREATE TABLEに明記された未対応のCOLLATE指定は消えません。エラー箇所に指定が残っているなら、その定義を確認します。

1273が消えても、次に一意制約で止まることがある

上の2行は、codeがalphaとalpha です。後者には末尾に空白があります。MySQLのutf8mb4_0900_ai_ciはNO PAD、utf8mb4_unicode_ciはPAD SPACEなので、等値比較での末尾空白の扱いが変わります。公式の末尾空白の説明にもこの差があります。

両方の照合順序があるMySQL側で比較すると、違いを確認できます。

SELECT
  _utf8mb4'alpha' COLLATE utf8mb4_0900_ai_ci = _utf8mb4'alpha ' AS original_equal,
  _utf8mb4'alpha' COLLATE utf8mb4_unicode_ci = _utf8mb4'alpha ' AS candidate_equal;

今回のMySQL 8.4の検証では、original_equalが0、candidate_equalが1でした。元のルールなら別の値、変更候補のルールなら同じ値と判定されます。これは等値比較の例で、LIKEの末尾空白の扱いまで同じだと考えないでください。

そのため、元のDDLでは入った2行が、修正後のDDLではUNIQUE KEY uq_codeに衝突します。エラーを無視したり、INSERT IGNOREへ変えたりする前に、失われる行がないか確認してください。照合順序の変更に合わせてどのデータを残すかは、このエラー解消だけでは決められません。

元の検証表で、変更候補では同じと判定される値を探すSQLです。

SELECT code COLLATE utf8mb4_unicode_ci AS compared_code,
       COUNT(*) AS matches,
       GROUP_CONCAT(HEX(code) ORDER BY id) AS original_bytes
FROM import_probe
GROUP BY code COLLATE utf8mb4_unicode_ci
HAVING COUNT(*) > 1;

matchesが2となり、original_bytesに616C706861,616C70686120が並びます。最後の20が空白です。実テーブルでは列名と照合順序を置き換え、複合一意キーなら対象の列の組み合わせで確認します。このSQLだけで全テーブルの互換性が確認できるわけではありません。

検証用DBで確認した結果と、実データで見る項目

2026年9月12日に、WordPress用DBとは別のDocker環境で上記の小さな表を確認しました。

環境・操作 結果
MySQL 8.4:元DDLと2行を実行 作成・挿入成功。末尾空白あり/なしは別の値
MySQL 5.7.44:元DDLを実行 ERROR 1273、0900名が未対応
MySQL 5.7.44:修正DDLと2行を実行 表作成は成功。INSERTはERROR 1062で一意制約に衝突
MariaDB 11.4.12:元DDLと2行を実行 別名として受け付け、2行とも挿入成功

この結果は小さな表の確認です。実データの移行では、件数だけでなく次の結果を元環境と比較します。

  • 一意キーが衝突しないか。大文字小文字、アクセント、末尾空白などを含めて確認する。
  • 検索、JOIN、GROUP BYで一致する行やまとまりが変わらないか。
  • ORDER BYの順序が業務上期待したものか。
  • 絵文字・日本語・CMSの本文や設定値が保存どおりに戻るか。
  • ビュー、トリガー、保存プログラムなども作成・実行できるか。

途中で止まったDBには、先に実行された文の結果が残る場合があります。同じDBへ何度も流し込んで成功を判定せず、検証先を作り直して、ダンプの最初から最後までエラーなく復元できることを確かめます。

対応名の確認から、比較結果の確認までで直す

Unknown collationを解消する順番は、移行先の対応確認 → 環境か照合順序の選択 → DDLだけの修正 → 空の検証DBへの復元 → 比較・一意性の確認です。MySQL 8系のダンプを5.7へ入れる場合、照合順序以外の構文や機能の互換性も別途確認が必要です。

照合順序の意味や通常の確認方法は、MySQLのCOLLATIONの意味と確認方法で確認できます。今回のエラーでは「インポートが通った」で終わらず、アプリが同じ値を同じように扱えるかまで確かめてから切り替えましょう。

スポンサーリンク