2026-05-23
utf8mb4とは?絵文字保存とMySQL文字コード対応の基本を徹底解説!
utf8mb4はMySQLで4バイトのUTF-8文字(絵文字や一部の漢字)まで保存できる文字セットです。utf8との違い・絵文字保存の仕組み・切り替え時の注意点を整理して解説します。
この記事の要点
- utf8mb4はMySQLで4バイトまでのUTF-8文字(絵文字を含む)を保存できる文字セット
- MySQLのutf8は3バイトまでしか扱えない別物(実体はutf8mb3)
- 絵文字は4バイトのためutf8カラムに保存すると途切れたり?になる
- MySQL 8.0以降はutf8mb3が非推奨で、新規アプリはutf8mb4を選ぶのが推奨
- 切り替え時は照合順序とインデックス長制限・接続側の文字コードを確認する
「問い合わせフォームに絵文字を入れたら本文が途中で消えた」「SNS から取り込んだ投稿の 🍣 が ? になっていた」。こうした症状の多くは、MySQL の文字コード設定を utf8mb4 に切り替えるだけで解決します。
絵文字を含む投稿を扱う SNS・問い合わせフォーム・コメント欄を運営するなら、utf8mb4 の理解は欠かせません。正しく設定するだけでデータ損失を防げます。
utf8mb4 とは(一言で)
utf8mb4 は MySQL(および MariaDB)で扱える「本物の UTF-8」を表す文字セット名です。mb4 は「multibyte 4」の略で、1 文字あたり最大 4 バイトまでの UTF-8 を許容する、という意味があります。
「utf8mb4 を使う」とは、テーブルやカラムの CHARACTER SET を utf8mb4 に指定することです。たとえば次のように CREATE TABLE で指定します。
CREATE TABLE messages (
id INT PRIMARY KEY AUTO_INCREMENT,
body TEXT
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
これだけで、本文に絵文字を含む投稿も欠損なく保存できます。
MySQL の utf8 と utf8mb4 の違い
| 項目 | utf8(実体は utf8mb3) | utf8mb4 |
|---|---|---|
| 1 文字あたりの最大バイト数 | 3 バイト | 4 バイト |
| 保存できる Unicode の範囲 | 基本多言語面(BMP, U+0000〜U+FFFF)のみ | BMP + 追加面(U+10000〜U+10FFFF) |
| 絵文字(😀 など)の保存 | できない | できる |
| 一部の漢字(𠮷・𩸽 など)の保存 | できない | できる |
| MySQL 8.0 での扱い | 非推奨(将来削除予定) | 推奨 |
MySQL における utf8 は歴史的な経緯で「3 バイト UTF-8」を意味する独自定義です。Web 標準の UTF-8(最大 4 バイト)とは別物で、これが初学者最大の混乱ポイントになっています。
Oracle 公式ドキュメントでも将来の変更が示唆されています。utf8mb3 のエイリアスである utf8 は、将来 utf8mb4 を指すよう変更される見込みです。
この名前のずれが原因で生まれた有名なバグが「寿司ビール問題」です。utf8 カラムでは 🍣(寿司)と 🍺(ビール)が同じ値として扱われます。JOIN や UNIQUE 制約で「別物のはずなのに同一」と判定される事故が報告されました。
なぜ絵文字は 4 バイトになるのか
UTF-8 は Unicode のコードポイントを 1〜4 バイトで可変長エンコードする方式です。コードポイントの範囲によって必要なバイト数が決まります。
| Unicode コードポイント | UTF-8 バイト数 | 例 |
|---|---|---|
| U+0000〜U+007F | 1 バイト | A, 9, ! |
| U+0080〜U+07FF | 2 バイト | ñ, ü, ギリシャ文字 |
| U+0800〜U+FFFF | 3 バイト | 一般的な漢字、ひらがな、カタカナ |
| U+10000〜U+10FFFF | 4 バイト | 絵文字 😀、𠮷・𩸽 など追加面の漢字 |
絵文字の多くは U+1F300 以上に割り当てられており、4 バイトの領域に入ります。SNS の 🍣 寿司は U+1F363、バイト列は F0 9F 8D A3 の 4 バイトです。utf8 カラムに INSERT すると、4 バイト目以降が捨てられて空文字や ? になる挙動が起きます。
文字のバイト数や Unicode コードポイントを確認したいときは、文字数カウンター にテキストを貼り付けてください。UTF-8 バイト数・文字数・書記素クラスタ数を一度に確認できます。
切り替えるときの注意点
1. 照合順序(COLLATION)の選択
utf8mb4 には複数の照合順序があります。代表的なものは以下の 3 つです。
utf8mb4_general_ci: 軽量だが言語ごとの並び順がやや荒いutf8mb4_unicode_ci: Unicode の正式な並び順に従う(精度が高い)utf8mb4_0900_ai_ci: MySQL 8.0 以降の最新規格。デフォルトとして推奨
MySQL 8.0 系なら utf8mb4_0900_ai_ci が推奨です。互換性重視なら utf8mb4_unicode_ci を選ぶのが無難です。
2. インデックス長制限
MySQL 5.6 以前の InnoDB は インデックスのキー長が 767 バイト に制限されていました。utf8mb4 は 1 文字 4 バイトのため、VARCHAR(255) のインデックスは 1020 バイトになります。これは 767 バイトの制限を超えます。
対応策は以下の通りです。
- MySQL 5.7 以降にアップグレードし、
innodb_large_prefix = ONとROW_FORMAT=DYNAMICまたはCOMPRESSEDを有効化(5.7.7 以降は既定で有効) - カラム長を
VARCHAR(191)以下にする(191 × 4 = 764 で 767 以内に収まる)
3. 既存テーブルの変換
既にデータが入っているテーブルを utf8mb4 に切り替えるときは、ALTER TABLE を流します。
ALTER DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE messages
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
大規模テーブルでは、コンバート中にロックがかかる場合があります。メンテナンス時間を確保するか、pt-online-schema-change などのオンライン DDL ツールを検討してください。
4. 接続側の文字コード
接続側でも SET NAMES utf8mb4 を発行するか、接続文字列に charset=utf8mb4 を含める必要があります。サーバ側だけ切り替えても、接続が utf8 のままだと絵文字が ? になります。
文字数とバイト数を確認する方法
ブラウザでテキストのバイト数を確認するには、TextEncoder を使う方法が確実です。
const text = '🍣 寿司';
const bytes = new TextEncoder().encode(text);
console.log(text.length); // 5(UTF-16 のコード単位数)
console.log(bytes.length); // 11(UTF-8 のバイト数: 4 + 1 + 3 + 3)
String.prototype.length は UTF-16 のコード単位数を返します。絵文字 1 文字でも length === 2 です。VARCHAR(N) の N が何バイトに相当するかを正確に見積もるには、UTF-8 バイト数で考える必要があります。
手元で素早く確認したいときは 文字数カウンター を使うとブラウザだけで集計できます。バイト数・文字数・書記素クラスタの数を同時に出すので、VARCHAR の容量設計やフォームのバリデーション設計に役立ちます。
使用例
たとえば、問い合わせフォームで「ありがとう😊」と送信したログが、DB 上で「ありがとう」と切れていた場面を考えます。body カラムが utf8 のままで、絵文字 😊 の 4 バイト目が捨てられているケースが多めです。utf8mb4 への切り替えと接続側の charset=utf8mb4 指定で、絵文字を含むメッセージも欠損なく保存できます。
まとめ
utf8mb4を最初から選んでおけば、絵文字や追加面の漢字を気にせずに保存できる- 既存システムで
utf8を使っているなら、ALTER TABLEでutf8mb4に変換しデータ損失リスクを下げる - 切り替え時はインデックス長制限と照合順序、接続側の文字コードを確認する
- 文字数とバイト数の差は 文字数カウンター で把握しておくと、フォームやカラム設計のミスを減らせる
絵文字に対応した SNS・問い合わせフォーム・コメント欄を運営するなら、utf8mb4 は実質的に必須の選択肢です。文字コードの扱いに悩むことがあれば、Base64で日本語が文字化けする理由とUTF-8 もあわせて参照してください。Web の文字コード周りの全体像をつかみやすくなります。