MySQLの文字コードをutf8mb4へ移行する手順|照合順序の選定と既存テーブルの変換

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)LinuxtipsMySQL > MySQLの文字コードをutf8mb4へ移行する手順|照合順序の選定と既存テーブルの変換
「MySQLに絵文字を保存しようとしたら文字化けした」「utf8mb4への移行で照合順序は何を選べばいい?」
既存DBをそのままにしてutf8mb4に移行しようとすると、設定ファイルの変更だけでは足りず、既存のデータベースとテーブルに対してALTER TABLE文を実行する必要があります。この手順を飛ばすと、新しく作成したテーブルだけが変換され、古いテーブルは旧charset(utf8)のまま混在する状態になります。

この記事では、MySQL 5.7・8.0共通のutf8mb4移行手順を、照合順序の選定から既存テーブルの一括変換まで順番に解説します。動作確認環境はRHEL 9.4 / Ubuntu 24.04 LTS(MySQL 8.0.40)です。

この記事のポイント

・MySQLの「utf8」は3バイト文字までで、絵文字など4バイト文字はutf8mb4が必要
・照合順序は5.7系ならutf8mb4_unicode_ci、8.0系ならutf8mb4_0900_ai_ciが推奨
・my.cnf変更後、既存DBとテーブルにALTER TABLEで変換しないと混在状態になる
・CONVERT TO CHARACTER SET文でテーブル内の全カラムを一括変換できる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

MySQLの「utf8」が3バイト文字しか扱えない理由

Linuxサーバー上で長年MySQLを運用してきた現場では、今でも文字セット設定に「utf8」と書かれた古いmy.cnfを見かけることがあります。しかしMySQLの「utf8」は、UTF-8規格の完全な実装ではありません。

MySQLの「utf8」(正確にはutf8mb3)は、1文字あたり最大3バイトまでしか扱えません。UTF-8では絵文字やBMP(基本多言語面)外の文字は4バイトが必要なため、これらをutf8カラムに保存しようとすると、無音で切り捨てられるか「Incorrect string value」エラーが発生します。

「utf8mb4」はMySQLの「utf8」を完全なUTF-8に拡張したcharsetです。4バイト文字(絵文字、CJK拡張漢字等)を正しく格納できます。MySQL 8.0以降ではサーバーのデフォルトがutf8mb4に変更されており、新規構築であれば追加設定不要ですが、MySQL 5.7以前からのDBを引き継いだ環境では明示的な移行作業が必要です。

照合順序(COLLATION)の選定

utf8mb4への移行で最も迷うのが照合順序の選択です。照合順序とは、文字列の比較・ソート方法を定義するルールで、同じ文字セットでも複数の選択肢があります。

主要な照合順序の比較

照合順序 対応バージョン 特徴
utf8mb4_unicode_ci 5.7 / 8.0 Unicode標準準拠。5.7系の移行先として最も安全
utf8mb4_0900_ai_ci 8.0以降のみ Unicode 9.0準拠。8.0のデフォルト。アクセント・大文字小文字非依存
utf8mb4_general_ci 5.7 / 8.0 処理が高速だが比較精度が低い。新規採用は非推奨
utf8mb4_bin 5.7 / 8.0 バイナリ比較。大文字小文字を区別したい場合に使う

選定の目安:
・MySQL 5.7環境からの移行 → utf8mb4_unicode_ci(既存のutf8_unicode_ciからの移行がスムーズ)
・MySQL 8.0環境(新規 or 8.0系のまま継続)→ utf8mb4_0900_ai_ci(デフォルト動作に合わせる)
・照合順序の混在を避けるために、DB全体を統一することが最優先です。

移行前の確認手順

1. 現在の文字コード設定を確認する

まずMySQLに接続して現在の設定を確認します。

mysql -u root -p mysql> SHOW VARIABLES LIKE 'character%'; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | utf8 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | utf8 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ 8 rows in set (0.00 sec) mysql> SHOW VARIABLES LIKE 'collation%'; +----------------------+-----------------+ | Variable_name | Value | +----------------------+-----------------+ | collation_connection | utf8_general_ci | | collation_database | utf8_general_ci | | collation_server | utf8_general_ci | +----------------------+-----------------+ 3 rows in set (0.00 sec)

2. 対象データベースの現在の文字コードを確認する

移行対象のDBとテーブルの文字コードを把握しておきます。

# データベースの文字コード確認 mysql> SHOW CREATE DATABASE mydb\G *************************** 1. row *************************** Database: mydb Create Database: CREATE DATABASE `mydb` /*!40100 DEFAULT CHARACTER SET utf8 */ 1 row in set (0.00 sec) # テーブルの文字コード一覧確認 mysql> SELECT table_name, table_collation FROM information_schema.tables WHERE table_schema = 'mydb'; +------------+-----------------+ | table_name | table_collation | +------------+-----------------+ | users | utf8_general_ci | | articles | utf8_general_ci | | orders | utf8_general_ci | +------------+-----------------+ 3 rows in set (0.00 sec)

移行対象テーブルと件数を把握した上で、大きいテーブルはALTER TABLE中のダウンタイムを見込んでおきましょう。

my.cnfの設定変更

1. my.cnfにutf8mb4を設定する

/etc/my.cnf(RHELの場合)または/etc/mysql/mysql.conf.d/mysqld.cnf(Ubuntu/Debianの場合)を編集します。

[mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci [client] default-character-set = utf8mb4 [mysql] default-character-set = utf8mb4

2. MySQLを再起動して設定を反映する

# RHEL / Rocky Linux / AlmaLinux の場合 sudo systemctl restart mysqld # Ubuntu / Debian の場合 sudo systemctl restart mysql

再起動後、SHOW VARIABLES LIKE 'character%'でサーバー側の設定がutf8mb4になっていることを確認します。

既存データベース・テーブルの変換

my.cnfを更新してもそれ以降に作成されるDB・テーブルにしか適用されません。既存のDBとテーブルは個別にALTER文で変換します。

1. データベースのデフォルト文字コードを変換する

mysql> ALTER DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; Query OK, 1 row affected (0.01 sec)

これは「DBのデフォルト設定」を変更するだけで、既存テーブルの文字コードは変わりません。テーブルの変換は次のステップが必要です。

2. 既存テーブルのcharsetを変換する

CONVERT TO CHARACTER SETを使うと、テーブル定義とすべてのVARCHAR・TEXT系カラムの文字コードを一度に変換できます。

# テーブルを1つずつ変換する場合 mysql> ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; Query OK, 0 rows affected (0.05 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> ALTER TABLE articles CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; Query OK, 0 rows affected (0.08 sec)

3. 全テーブルを一括変換するSQLを生成する

テーブル数が多い場合は、information_schemaからALTER文を自動生成して実行します。

# 変換用SQLの生成(出力結果をコピーして実行する) mysql> SELECT CONCAT( 'ALTER TABLE `', table_name, '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;' ) AS sql_stmt FROM information_schema.tables WHERE table_schema = 'mydb' AND table_type = 'BASE TABLE'; +-------------------------------------------------------------------+ | sql_stmt | +-------------------------------------------------------------------+ | ALTER TABLE `users` CONVERT TO CHARACTER SET utf8mb4 ... | | ALTER TABLE `articles` CONVERT TO CHARACTER SET utf8mb4 ... | | ALTER TABLE `orders` CONVERT TO CHARACTER SET utf8mb4 ... | +-------------------------------------------------------------------+ 3 rows in set (0.00 sec)

4. 変換後の確認

ALTER TABLE後、すべてのテーブルがutf8mb4になっていることを確認します。

mysql> SELECT table_name, table_collation FROM information_schema.tables WHERE table_schema = 'mydb'; +------------+--------------------+ | table_name | table_collation | +------------+--------------------+ | users | utf8mb4_unicode_ci | | articles | utf8mb4_unicode_ci | | orders | utf8mb4_unicode_ci | +------------+--------------------+ 3 rows in set (0.00 sec) mysql> SHOW VARIABLES LIKE 'character%'; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | utf8mb4 | | character_set_connection | utf8mb4 | | character_set_database | utf8mb4 | | character_set_filesystem | binary | | character_set_results | utf8mb4 | | character_set_server | utf8mb4 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ 8 rows in set (0.00 sec)

character_set_systemutf8のままですが、これはMySQLサーバー内部が使うメタデータ用のcharsetであり、正常です。変更する必要はありません。

移行時の注意点

ALTER TABLE中のテーブルロック
CONVERT TO CHARACTER SETの実行中は対象テーブルへの書き込みがブロックされます。大きいテーブル(数百万行以上)では数分~数十分かかる場合があります。本番環境では必ずオフピーク時に実施し、事前にmysqldumpでバックアップを取得してください。

アプリ側の接続設定も更新する
MySQLサーバーの設定を変えても、アプリ側のDB接続文字列でcharsetを旧設定のまま指定していると「Illegal mix of collations」エラーが発生します。PHPならcharset=utf8mb4、Pythonならcharset='utf8mb4'と接続パラメータを確認してください。現場でよくある「設定は変えたのにエラーが出る」パターンも含め、Linuxサーバー運用の体系的な知識を短期間で固めたい方には、【初心者向けハンズオンセミナー】が役立ちます。

innodb_large_prefix(MySQL 5.7)の確認
MySQL 5.7でInnoDB・RowFormat=CompactのままVARCHAR(255)のカラムにインデックスを張ると、utf8mb4では1文字4バイトになるため 255×4=1020バイトがkey_length上限の767バイトを超えてエラーになります。以下をmy.cnf[mysqld]に追加して対処してください。

# MySQL 5.7 のみ必要(MySQL 8.0ではデフォルトで不要) innodb_large_prefix = ON innodb_file_format = Barracuda innodb_file_per_table = ON

トラブルシュート

「Incorrect string value: '\\xF0...' for column 'xxx'」エラー
保存しようとしている文字列に4バイト文字(絵文字等)が含まれているが、該当カラムがutf8(utf8mb3)のままになっているケースです。SHOW CREATE TABLE テーブル名でカラムのcharsetを確認し、変換漏れがないか確認します。特定のカラムだけを変換したい場合は以下のように実行します。

# 特定カラムのみ変換する場合 mysql> ALTER TABLE users MODIFY COLUMN profile TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; Query OK, 0 rows affected (0.03 sec)

「Illegal mix of collations」エラー
接続文字コードとDBのcollationが一致していない場合に発生します。MySQLクライアントでSET NAMES utf8mb4を実行してエラーが解消するなら、アプリの接続設定が原因です。

# 接続文字コードの一時変更で確認 mysql> SET NAMES utf8mb4; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM users WHERE name = 'テスト';

「Specified key was too long; max key length is 767 bytes」エラー
前述のinnodb_large_prefix問題です。MySQL 8.0環境では発生しません。MySQL 5.7ではinnodb_large_prefix=ONを設定するか、インデックスのprefix長を191以下(767÷4=191文字)に制限します。

# インデックスのprefix長を191文字以内に制限する例 mysql> ALTER TABLE users ADD INDEX idx_name (name(191));

本記事のまとめ

やりたいこと コマンド・設定
現在の文字コード設定を確認する SHOW VARIABLES LIKE 'character%';
照合順序の設定を確認する SHOW VARIABLES LIKE 'collation%';
サーバーのデフォルトをutf8mb4に変更する my.cnfにcharacter-set-server=utf8mb4を追記してrestart
既存DBの文字コードを変換する ALTER DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
既存テーブルの文字コードを変換する ALTER TABLE tbl CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
特定カラムの文字コードを変換する ALTER TABLE tbl MODIFY COLUMN col TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
テーブルの変換後を確認する SELECT table_name, table_collation FROM information_schema.tables WHERE table_schema='mydb';

utf8mb4移行のポイントは3段階に分かれます。①my.cnfでサーバーのデフォルト文字コードを変更する、②既存のDBにALTER DATABASEを実行する、③既存の各テーブルにCONVERT TO CHARACTER SETを実行する。この3つをすべて実施しないと、新旧のcharsetが混在してCollation不一致エラーが出続けます。

照合順序はMySQL 5.7環境ではutf8mb4_unicode_ci、MySQL 8.0環境ではutf8mb4_0900_ai_ci(またはunicode_ci)を選ぶのが実務上の定石です。既存DB(5.7)を8.0へ移行するタイミングでcollationを揃えると、後から整合性の問題が発生しにくくなります。

MySQLの文字コード移行を理解したら、次はLinuxサーバー全体の運用スキルを体系的に固めませんか?

DB設定・バックアップ・レプリケーションなど、現場で必要なDB運用の知識も含め、現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。

「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。