MySQL 8のユーザー作成と権限付与の“いまの正解”

こんにちは、さるまりんです🐒

MySQL 8 でユーザーと権限を設定しようとして、

ERROR 1064 (42000) ... near 'IDENTIFIED BY'

のようなエラーに出会いました。
これはMySQL 5 時代の書き方がそのまま使えないからです。

今回は いまの正しい手順 をコンパクトにまとめます。最初に“そのまま使えるテンプレ”を置き、続いてよくあるつまずき確認コマンド最小権限の考え方を整理します。

これからやるのは?

  • MySQL 8 ではユーザー作成/更新CREATE/ALTER USER)と 権限付与GRANT)を**分けて書く**必要があります。
  • GRANT ... IDENTIFIED BYは **構文エラー**になります。
  • 何度流しても安全なコピペ用テンプレを持っておくと便利です。

背景:なぜ変わった?

MySQL 8 ではセキュリティ設計が整理され、「ユーザー管理」と「権限付与」を別コマンドに分離する方針になりました。
そのため、以前のようにGRANT ... IDENTIFIED BY 'password'と一体で書くとエラーになります。

すぐ使える初期化テンプレ(Docker想定)

開発・検証用途でよく使う形です。.envは例なので、環境に合わせて置き換えてください。

DB_NAME=appdb
DB_USER=appuser
DB_PASSWORD=secret
DB_ROOT_PASSWORD=rootsecret

DB作成 → ユーザー作成/更新 → 権限付与

docker compose exec -T db mysql -uroot -p"$DB_ROOT_PASSWORD" -e "\
  DROP DATABASE IF EXISTS \`$DB_NAME\`;
  CREATE DATABASE \`$DB_NAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  CREATE USER IF NOT EXISTS '$DB_USER'@'%' IDENTIFIED BY '$DB_PASSWORD';
  ALTER USER '$DB_USER'@'%' IDENTIFIED BY '$DB_PASSWORD';
  GRANT ALL PRIVILEGES ON \`$DB_NAME\`.* TO '$DB_USER'@'%';
  • DROP DATABASE破壊的なので本番では使いません(開発時のやり直し用)。
  • IF NOT EXISTSALTER USERをセットにしておくと、何度流しても通るので安心。
  • 文字コードは基本的にutf8mb4を使うのがおすすめです。
  • 接続元は Docker なら'%'(任意ホスト)が扱いやすいです。

注意-p "$PASS"のように-pとパスワードの間に空白を入れると失敗します。正しくは -p"$PASS"(同じ引数にまとめる)です。

最小権限で運用したいとき

アプリが必要とする権限だけを渡すのが理想です。
例えば「読み書き+テーブル作成・変更だけ」で足りるなら:

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX
ON `appdb`.*
TO 'appuser'@'%';

不要なDROPCREATE ROUTINEなどは付けない、が基本です。
要件が固まったら SHOW GRANTS → 見直しを回していきます。

よくあるエラーと直し方

1064(`… near ‘IDENTIFIED BY’`)

原因GRANT ... IDENTIFIED BYを使っている
解決CREATE/ALTER USERGRANTを分離する

1045(`Access denied for user ‘-p’@’localhost’`)

原因:コマンドで-p $PASS空白を入れてしまった
解決-p"$PASS"と一引数にまとめる

1396(`Operation CREATE USER failed`)

原因:ユーザーが既に存在
解決IF NOT EXISTSを付ける、またはDROP USER 'user'@'host';ののちCREATE USER(DROPは注意!)

1130(`Host … is not allowed to connect`)

原因'user'@'host'host部分が一致していない
解決:接続元に合わせて'%'や具体的なホストで作成・付与し直す

できたか確認

できているかをチェックするためのクエリです。

-- ユーザーの存在と認証方式を確認(root で)
SELECT user, host, plugin FROM mysql.user WHERE user='appuser';

-- 付与済み権限を確認
SHOW GRANTS FOR 'appuser'@'%';

MySQL 8 の既定の認証プラグインは caching_sha2_passwordです。
古いクライアントで接続できない場合は(開発用途に限り)
ALTER USER 'appuser'@'%' IDENTIFIED WITH mysql_native_password BY 'secret';
のように変更する手もあります(本番では非推奨です)。

ちょっとおまけ

運用のちょっとしたコツです。

パスワードの扱い
履歴に残したくない場面はmysql_config_editor.my.cnf、CIのシークレットを活用します。

Docker とホスト名
コンテナ間ではlocalhostではなくサービス名でアクセスします。ユーザー作成時の@'host'と、アプリ側の接続先が一致しているか確認を。

スクリプト化
初期化を繰り返す前提で、IF NOT EXISTS / ALTER USER / FLUSH PRIVILEGESを組み込んでおくとラクです。

小さなリファレンス

  • ユーザー作成:CREATE USER 'u'@'%' IDENTIFIED BY 'p';
  • 既存のPW変更:ALTER USER 'u'@'%' IDENTIFIED BY 'p';
  • 権限付与:GRANT <privileges> ON db.* TO 'u'@'%';
  • 取り消し:REVOKE <privileges> ON db.* FROM 'u'@'%';
  • 確認:SHOW GRANTS FOR 'u'@'%';
  • 削除:DROP USER 'u'@'%';

MySQL 8 ではユーザー管理と権限管理は別、って覚えておくのが良さそうですね。
いつものやり方でエラーが出ると慌てがちですが、何度流しても安全なコピペ用テンプレが手元にあれば落ち着けます。
エラーも原因がパターン化しているので、順番に潰していけば大丈夫。

やってみて失敗して考えて、その結果を残しておくの、大事だなと改めて思いました。

読んでくださってありがとうございます。

それではまた! 🐒