【MySQL】ユーザー権限管理:GRANT・REVOKEの基本

MySQL

こんにちは、かつコーチです。

「アプリのDB接続用ユーザーに、うっかりrootを使い続けていませんか」

開発中はつい楽なのでrootユーザーで全部済ませてしまいがちですが、これは本番運用ではかなり危険な状態です。

もしアプリにSQLインジェクションの脆弱性があった場合、root権限のままだと被害がテーブルの中身だけでなく、ユーザー管理やサーバー設定にまで及んでしまいます。

この記事では、MySQLのユーザー権限管理の基本であるGRANT(権限を付与するコマンド)とREVOKE(権限を剥奪するコマンド)の使い方を解説します。

「必要な権限だけを、必要なユーザーにだけ与える」という考え方は、セキュリティの世界で最小権限の原則(ユーザーには業務上必要最低限の権限だけを与えるという考え方)と呼ばれる基本中の基本です。

MySQLの権限管理の仕組み

ユーザーとホストの組み合わせで権限が決まる

MySQLでは、ユーザーは単なる「ユーザー名」ではなく、「ユーザー名 + 接続元ホスト」の組み合わせで識別されます。

-- 'app_user'@'localhost' と 'app_user'@'%' は別ユーザー扱い
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'StrongPassw0rd!';
CREATE USER 'app_user'@'%' IDENTIFIED BY 'StrongPassw0rd!';

localhostはそのサーバー上からの接続のみ許可、%はどこからでも接続を許可という意味です。

同じユーザー名でも接続元が違えば別ユーザーとして扱われるため、権限も個別に設定する必要があります。

権限の階層(グローバル・データベース・テーブル・カラム)

MySQLの権限は、大きく分けて4段階の階層で管理できます。

階層指定方法用途
グローバル*.*サーバー全体に対する権限(管理用ユーザー向け)
データベース単位dbname.*特定のDBだけへのアクセス許可
テーブル単位dbname.tablename特定のテーブルだけへのアクセス許可
カラム単位SELECT(col1, col2)特定のカラムだけの読み取り許可

アプリケーション用のユーザーは、基本的に「データベース単位」で権限を絞るのが実務上の標準的な運用です。

GRANTで権限を付与する

基本の書き方

GRANT文の基本構文は次の通りです。

GRANT 権限リスト ON データベース.テーブル TO 'ユーザー名'@'ホスト';

例えば、アプリケーション用ユーザーにmyappデータベースへのCRUD操作(作成・読み取り・更新・削除)権限だけを与えるには、次のように書きます。

GRANT SELECT, INSERT, UPDATE, DELETE ON myapp.* TO 'app_user'@'%';

このユーザーは、myappデータベース内のデータ操作はできますが、テーブルの作成・削除(CREATEDROP)やユーザー管理はできません。

権限の種類を目的別に把握する

よく使う権限は次の通りです。

権限意味想定ユーザー
SELECTデータの読み取り全アプリユーザー
INSERTデータの追加書き込みを行うアプリユーザー
UPDATEデータの更新同上
DELETEデータの削除同上
CREATEテーブル・DBの作成マイグレーション実行ユーザー
ALTERテーブル構造の変更同上
DROPテーブル・DBの削除開発環境の管理者のみ
ALL PRIVILEGESすべての権限管理者ユーザーのみ

「読み取り専用のレポート用ユーザー」を作りたい場合は、SELECT権限だけを与えます。

CREATE USER 'report_user'@'%' IDENTIFIED BY 'ReportPass123!';
GRANT SELECT ON myapp.* TO 'report_user'@'%';
FLUSH PRIVILEGES;

FLUSH PRIVILEGESは権限テーブルの変更をすぐに反映させるコマンドです。

MySQL 8.0以降はGRANT実行時に自動で反映される場合が多いですが、権限テーブルを直接編集した場合などは明示的に実行しておくと安心です。

つまずきやすい設定・注意点

権限設定でよくあるつまずきが、存在しないユーザーへのGRANTです。

ERROR 1133 (42000): Can't find any matching row in the user table

これはMySQL 5.7以前でよく見たエラーで、GRANT文がユーザー作成を兼ねていた古い仕様に依存したコードをMySQL 8.0で実行すると発生します。

MySQL 8.0ではGRANTとユーザー作成が分離されているため、必ずCREATE USERを先に実行してからGRANTを行う必要があります。

-- ❌ Before:MySQL 8.0ではエラーになる書き方(5.7以前の癖が残っている)
GRANT SELECT ON myapp.* TO 'new_user'@'%' IDENTIFIED BY 'pass123';
-- ✅ After:CREATE USERとGRANTを分離する
CREATE USER 'new_user'@'%' IDENTIFIED BY 'pass123';
GRANT SELECT ON myapp.* TO 'new_user'@'%';

筆者もマイグレーションスクリプトを古いMySQL 5.7時代のまま流用してこのエラーに遭遇したことがあります。

MySQL 8.0系のマニュアルやチュートリアルを参照する際は、バージョンが古い情報でないか必ず確認するようにしています。

REVOKEで権限を剥奪する

基本の書き方

不要になった権限を取り消すにはREVOKE文を使います。

REVOKE 権限リスト ON データベース.テーブル FROM 'ユーザー名'@'ホスト';

例えば、先ほどのapp_userからDELETE権限だけを取り消したい場合は次のようにします。

REVOKE DELETE ON myapp.* FROM 'app_user'@'%';

論理削除(deleted_atカラムで削除フラグを立てる設計)を採用しているアプリでは、そもそもアプリ用ユーザーに物理削除のDELETE権限を与えない、という運用も有効です。

権限の確認方法

現在どの権限が付与されているかはSHOW GRANTSで確認できます。

SHOW GRANTS FOR 'app_user'@'%';
+---------------------------------------------------------------+
| Grants for app_user@%                                         |
+---------------------------------------------------------------+
| GRANT USAGE ON *.* TO `app_user`@`%`                           |
| GRANT SELECT, INSERT, UPDATE ON `myapp`.* TO `app_user`@`%`    |
+---------------------------------------------------------------+

REVOKEを実行した後は、必ずSHOW GRANTSで意図通りに権限が変わっているか確認する習慣をつけましょう。

権限まわりの操作は、確認を怠ると「権限が足りずアプリが動かない」「逆に権限が残ったまま気づかない」といったトラブルにつながりやすい部分です。

応用・一歩先の使い方(中級読者向けブリッジ)

ロールを使った権限管理(MySQL 8.0の新機能)

MySQL 8.0からはロール(複数の権限をまとめた「権限のグループ」)という仕組みが使えるようになりました。

ユーザーが増えるたびに同じGRANT文を繰り返すのは非効率なので、ロールを使うと管理がぐっと楽になります。

-- ロールを作成し、権限をまとめる
CREATE ROLE 'app_readonly';
GRANT SELECT ON myapp.* TO 'app_readonly';

-- ユーザーにロールを割り当てる
CREATE USER 'analyst1'@'%' IDENTIFIED BY 'Pass1234!';
GRANT 'app_readonly' TO 'analyst1'@'%';

-- ロールを有効化(デフォルトで有効にする場合)
SET DEFAULT ROLE 'app_readonly' TO 'analyst1'@'%';

分析担当者が増えるたびに同じGRANT SELECTを書く必要がなくなり、「このロールを割り当てる」だけで済むのが利点です。

チームの人数が増えてくるフェーズでは、ロールベースの権限管理に切り替えることを検討してみてください。

まとめ

この記事のポイント

  • MySQLの権限は「ユーザー名 + 接続元ホスト」の組み合わせで識別される
  • アプリ用ユーザーにはrootを使わず、必要な権限だけをGRANTで絞って与える
  • MySQL 8.0ではCREATE USERGRANTが分離されているため、古い書き方のまま流用するとエラーになる
  • REVOKEで不要な権限を剥奪し、SHOW GRANTSで必ず結果を確認する
  • ユーザー数が増えてきたら、MySQL 8.0の「ロール」機能で管理をまとめると効率的

次に読むべき記事

  • SQLインジェクション対策とプレースホルダの使い方
  • よくあるMySQLエラーまとめ(Access denied等)

タグ: MySQL, 中級者向け, セキュリティ

タイトルとURLをコピーしました