2026年9月15日
2026年9月15日
MySQLの文字コード(charset)と照合順序(collation)を変更する手順
MySQL の文字コード(character set、charset)は文字をどのバイト列で保存するか、照合順序(collation)は文字どうしをどう比べて並べるかを決める設定です。絵文字が保存できない、? に置き換わる、検索で大文字と小文字が区別される・されない、といった問題はこの2つで決まります。この記事の内容は、2026年11月時点で MySQL 8.4 の公式マニュアルで確認し、SQL は MySQL 8.4 で動かして確かめています。
設定は4つの段階にある
文字コードと照合順序は、次の4つの段階でそれぞれ持っています。下の段階で指定が無いと、1つ上の段階の値が使われます。
| 段階 | 決まるタイミング | 変える方法 |
|---|---|---|
| サーバー | MySQL の起動時 | 設定ファイルの character-set-server・collation-server |
| データベース | CREATE DATABASE のとき |
ALTER DATABASE(これから作るテーブルの既定だけが変わる) |
| テーブル | CREATE TABLE のとき |
ALTER TABLE ... CONVERT TO(既存の列も変換する) |
| 列 | 列を作ったとき | ALTER TABLE ... MODIFY(その列だけ) |
実際にデータの保存に使われるのは列の設定です。データベースやサーバーの設定を変えても、すでにある列は変わりません。
このほかに、クライアントとの通信に使う文字コード(character_set_client・character_set_connection・character_set_results)があります。ここが列と食い違うと、保存や表示のときに文字化けします。
ステップ1:今の設定を確かめる
-- サーバーと接続の設定
SHOW VARIABLES LIKE 'character_set_%';
SHOW VARIABLES LIKE 'collation_%';
-- データベースの既定
SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM information_schema.SCHEMATA
WHERE SCHEMA_NAME = 'mydb';
-- テーブルの既定の照合順序
SELECT TABLE_NAME, TABLE_COLLATION
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'mydb';
-- 列ごとの設定(実際に保存に使われる値)
SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'mydb' AND CHARACTER_SET_NAME IS NOT NULL;
mydb は自分のデータベース名に置き換えます。1つのテーブルの定義をまとめて見るなら SHOW CREATE TABLE テーブル名; が便利です。
どの文字コード・照合順序にするか
文字コードは utf8mb4 を選びます。絵文字や一部の漢字のような4バイトの文字も保存できます。MySQL の utf8 は utf8mb3(3バイトまで)の別名で、4バイトの文字は保存できず、utf8mb3 自体も非推奨になっています。MySQL 8.0 以降は、サーバーの既定の文字コードが utf8mb4、既定の照合順序が utf8mb4_0900_ai_ci です。
主な照合順序の違いは次のとおりです。
| 照合順序 | 特徴 |
|---|---|
utf8mb4_0900_ai_ci |
MySQL 8.0 以降の既定。アクセント(濁点・半濁点を含む)と大文字小文字を区別しない |
utf8mb4_ja_0900_as_cs |
日本語向け。アクセントと大文字小文字を区別する。ひらがなとカタカナは同じとして並べる |
utf8mb4_ja_0900_as_cs_ks |
上に加えて、ひらがなとカタカナも区別する |
utf8mb4_bin |
バイト列のまま比べる |
utf8mb4_unicode_ci・utf8mb4_unicode_520_ci |
古い規格に基づく照合順序。MariaDB でも使える |
_ai_ci の照合順序では、たとえば「ハハ」と「パパ」が同じ文字列として比べられます。検索や一意制約(UNIQUE)でこれを区別したい列は、utf8mb4_ja_0900_as_cs などを指定します。照合順序を変えると、一意制約に違反する行が出て ALTER TABLE が失敗することもあるので、先に重複を確かめます。
0900 の付く照合順序は、文字列の末尾の空白も1文字として比べます('a' と 'a ' は別の文字列)。古い照合順序から変えると、空白の扱いの違いで検索結果が変わる場合があります。MariaDB や MySQL 5.7 と同じデータベースを共有する場合は、相手が対応している照合順序を選びます。
ステップ2:作業の前にバックアップを取る
文字コードの変換は、テーブルを作り直す重い処理で、元に戻すにはバックアップが必要です。
mysqldump -u root -p --single-transaction mydb > ~/mydb-before-charset.sql
-p だけを付けると、パスワードを聞かれます。コマンドラインにパスワードを直接書かないようにします。
ステップ3:データベースの既定を変える
ALTER DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
これで変わるのは、これから作るテーブルの既定だけです。既存のテーブルと列はそのままです。
新しくデータベースを作る場合は、最初から指定します。
CREATE DATABASE newdb CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
ステップ4:既存のテーブルと列を変換する
テーブルの既定と、テーブル内の文字列の列をまとめて変換するには CONVERT TO を使います。
ALTER TABLE posts CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
CONVERT TO を付けずに ALTER TABLE posts CHARACTER SET utf8mb4; とすると、テーブルの既定が変わるだけで、既存の列は変換されません。
1つの列だけを変える場合は MODIFY を使います。このとき、元の列の NOT NULL や DEFAULT も書き直さないと消えてしまいます。
ALTER TABLE posts
MODIFY title VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_ja_0900_as_cs NOT NULL;
データベースの中のテーブルをまとめて変換したい場合は、変換用の SQL を生成して中身を確かめてから実行します。
SELECT CONCAT('ALTER TABLE `', TABLE_NAME,
'` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;')
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'mydb' AND TABLE_TYPE = 'BASE TABLE';
変換するときの注意
- 文字コードや照合順序を変える ALTER TABLE は、テーブルを丸ごとコピーして作り直します(
ALGORITHM=COPY)。大きなテーブルでは時間がかかり、その間テーブルへの書き込みは止まります。アクセスの少ない時間帯に行います。 - utf8mb3 や latin1 から utf8mb4 にすると、1文字あたりの最大バイト数が増えます。
TEXTの列は、収まるようにMEDIUMTEXTに変わることがあります。 - InnoDB のインデックスの長さには上限があります(行フォーマットが
DYNAMICなどなら3072バイト、古いCOMPACT・REDUNDANTなら767バイト)。utf8mb4 は1文字4バイトで計算されるので、767バイトの環境ではVARCHAR(255)の列にインデックスを張れません。SHOW TABLE STATUSのRow_formatを確かめ、必要ならインデックスを前方191文字に限るなどの対処をします。 - 変換元にない文字があるとデータが失われることがあります。変換の前後で、行数と主要な列の内容を比べます。
すでに文字化けしているデータの場合
CONVERT TO は、列の文字コードとして正しく保存されているデータを別の文字コードに変換します。たとえば、列は latin1 なのに中身は UTF-8 のバイト列が入っている(接続の設定を誤って保存した)場合に CONVERT TO を実行すると、二重に変換されて直らなくなります。
このような場合は、いったんバイナリ型にして文字コードの指定を外し、正しい文字コードの型に戻します(MySQL の公式マニュアルが示している方法です)。
-- 中身は UTF-8 なのに latin1 の列として作られている title を直す例
ALTER TABLE posts MODIFY title VARBINARY(800);
ALTER TABLE posts MODIFY title VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL;
バイナリ型は、元の列の最大バイト数以上の長さにします(TEXT の列なら BLOB、MEDIUMTEXT なら MEDIUMBLOB)。1つの列に複数の文字コードのデータが混ざっていると、この方法では直せません。試す前にバックアップを取り、まず複製したテーブルで確かめます。WordPress の文字化けについては WordPressのデータベースの文字化けを直す方法 も参照してください。
ステップ5:設定ファイルでサーバーの既定を変える
サーバーの既定を変えると、文字コードを指定せずに作るデータベースの既定がそれになります。設定ファイルの場所は環境によって違います。
| 環境 | 主な設定ファイル |
|---|---|
| Ubuntu/Debian の MySQL | /etc/mysql/mysql.conf.d/mysqld.cnf |
| RHEL 系の MySQL | /etc/my.cnf または /etc/my.cnf.d/ の中のファイル |
| Windows | MySQL のデータディレクトリなどにある my.ini |
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_0900_ai_ci
[client]
default-character-set = utf8mb4
[client] の default-character-set は、mysql コマンドなどのクライアントが接続するときの文字コードです。変更後に MySQL を再起動し(Ubuntu なら sudo systemctl restart mysql)、ステップ1の SQL で値を確かめます。
アプリケーションからの接続では、接続のときに文字コードを指定します。PHP の PDO なら DSN に charset=utf8mb4 を付けます。
WordPress のデータベースの場合
WordPress は wp-config.php の次の2つで、接続の文字コードと照合順序を決めます。
<?php
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );
DB_COLLATE を空にすると、データベースの既定の照合順序が使われます。WordPress 4.2 以降は、データベースが対応していればテーブルを utf8mb4 で作ります。utf8(utf8mb3)の列だけでできた古いテーブルは WordPress のアップデート処理で utf8mb4 に変換されますが、latin1 などの列を含むテーブルは変換の対象外です(WordPress のソースコードの maybe_convert_table_to_utf8mb4() で確認)。テーブルを手作業で変換するのは、こうした古い設定のテーブルが残っている場合です。wp-config.php を変える前に、テーブルの列が実際にどの文字コードなのかをステップ1の SQL で確かめてください。
まとめ
- 文字コードと照合順序は、サーバー・データベース・テーブル・列の4段階にあり、保存に使われるのは列の設定です。
ALTER DATABASEはこれから作るテーブルの既定だけを変えます。既存のテーブルはALTER TABLE ... CONVERT TOで変換します。- 文字コードは utf8mb4 にします。照合順序は、比較のしかた(濁点・かな・大文字小文字の区別)に合わせて選びます。
- 変換の前にバックアップを取り、インデックスの長さと一意制約の重複を確かめます。
- すでに文字化けしているデータは
CONVERT TOでは直りません。バイナリ型を経由する方法を、複製したテーブルで試してから行います。