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 では直りません。バイナリ型を経由する方法を、複製したテーブルで試してから行います。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲