既存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文でテーブル内の全カラムを一括変換できる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
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)
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)
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_systemがutf8のままですが、これは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)
接続文字コードとDBのcollationが一致していない場合に発生します。MySQLクライアントで
SET NAMES utf8mb4を実行してエラーが解消するなら、アプリの接続設定が原因です。# 接続文字コードの一時変更で確認 mysql> SET NAMES utf8mb4; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM users WHERE name = 'テスト';
前述の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日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:MySQLのスロークエリログを有効化して遅いSQLを特定する方法|出力設定からmysqldumpslowとEXPLAINまで
- この記事の属するカテゴリ:MySQLへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます