タイトル: SQLSTATE[HY000] [1045] Access denied for user 'homestead'@'localhost'
SEOタイトル: SQLSTATE[HY000] [1045] Access denied for user の対処
| この記事の要点 |
|
エラー内容
SQLSTATE[HY000] [1045] Access denied for user 'homestead'@'localhost' (using password: YES)
Laravel で php artisan migrate を実行したときや、DB にアクセスするページを開いたときに発生します。1045 は MySQL のエラー番号で「認証に失敗した」ことを意味します。DB サーバーまでは届いているが、ユーザー名・パスワード・接続元ホストの組み合わせが認められなかった状態です。
末尾の (using password: YES) はパスワードを送ったが一致しなかったこと、(using password: NO) はパスワードが空のまま接続しようとしたことを表します。NO になっている場合は DB_PASSWORD が読み込まれていない可能性が高いです。
原因
ユーザー名が 'homestead' になっているのは、Laravel の古いバージョンの .env.example に、開発用仮想環境 Laravel Homestead 向けの初期値(ユーザー homestead / パスワード secret)が書かれていたためです。Homestead を使っていない環境でこの値のまま接続すると、MySQL にそのユーザーが存在せずエラーになります。
| 原因 | 見分け方 |
|---|---|
| .env の DB_USERNAME / DB_PASSWORD が実際の DB と違う | エラーのユーザー名が 'homestead' や 'root' など想定外になっている |
| 設定キャッシュが古い値のまま | .env を書き換えてもエラーのユーザー名が変わらない |
| MySQL にユーザーが作られていない・権限がない | mysql コマンドでも同じユーザーでログインできない |
| 接続元ホストが合っていない | 'user'@'%' はあるが 'user'@'localhost' はない、などホスト部分が違う |
| パスワードの記号が .env で正しく読まれない | パスワードに # や空白、引用符が含まれている |
| Docker 環境で接続先を間違えている | コンテナ内から 127.0.0.1 に接続し、別の MySQL に当たっている |
対処法
1. .env の DB 設定を実際の値に直す
プロジェクトのルートディレクトリ直下にある .env ファイルの DB 設定を、実際に使う MySQL の値に変更します。以下は Homestead の初期値の例です。
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
自分で作った DB を使う場合は、たとえば次のように書き換えます。パスワードに # や空白などの記号を含む場合は、ダブルクォートで囲むと安全です。
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=myapp
DB_USERNAME=myapp_user
DB_PASSWORD="p@ss#word"
なお Laravel 11 以降の新規プロジェクトは初期状態で DB_CONNECTION=sqlite になっています。MySQL を使う場合は DB_CONNECTION を mysql に変え、DB_HOST 以下の行のコメント(先頭の #)も外します。
2. 設定キャッシュをクリアする
過去に php artisan config:cache を実行していると、Laravel は .env ではなく bootstrap/cache/config.php の値を使います。.env を直しても反映されないときは、キャッシュを消します。
php artisan config:clear
# 本番環境では、確認後にあらためてキャッシュを作る
php artisan config:cache
php artisan serve や Docker コンテナ、キューワーカーなど常駐しているプロセスは、起動時の設定を持ち続けるので再起動も必要です。
3. MySQL 側にユーザーと権限を作る
ユーザーが存在しない場合は、MySQL に管理者でログインして作成します。MySQL 8.0 以降は GRANT 文でユーザー作成とパスワード設定を同時に行う書き方(IDENTIFIED BY 付きの GRANT)が廃止されたため、2 段階で実行します。
CREATE DATABASE myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'myapp_user'@'localhost' IDENTIFIED BY 'p@ss#word';
GRANT ALL PRIVILEGES ON myapp.* TO 'myapp_user'@'localhost';
-- 既存ユーザーのパスワードを変える場合
-- ALTER USER 'myapp_user'@'localhost' IDENTIFIED BY '新しいパスワード';
MySQL のユーザーは「ユーザー名+接続元ホスト」の組で管理されます。'myapp_user'@'localhost' と 'myapp_user'@'%' は別のユーザーとして扱われ、パスワードも別々です。どのホストで登録されているかは次の SQL で確認できます。
SELECT user, host, plugin FROM mysql.user WHERE user = 'myapp_user';
4. Docker / Laravel Sail の場合
Laravel Sail や docker compose で MySQL を動かしている場合、アプリのコンテナから見た 127.0.0.1 はアプリのコンテナ自身です。DB_HOST には compose ファイルのサービス名(Sail の初期値は mysql)を指定します。Sail の初期ユーザーは sail / パスワード password です。また MySQL コンテナはデータボリュームが空のときだけ環境変数からユーザーを作るため、後から .env のパスワードを変えても既存のボリュームには反映されません。
確認方法
- .env と同じ値で mysql コマンドから接続できるか確かめます。ここで失敗するなら Laravel ではなく MySQL 側の問題です
mysql -h 127.0.0.1 -P 3306 -u myapp_user -p myapp
- Laravel が実際に読み込んでいる設定値を確認します
php artisan tinker
>>> config('database.connections.mysql.username')
>>> DB::connection()->getPdo();
getPdo() がエラーなく PDO オブジェクトを返せば接続は成功しています。最後に php artisan migrate を実行してエラーが出ないことを確認します。
よく似た別のエラー
- SQLSTATE[HY000] [2002] Connection refused: 認証以前に DB サーバーに届いていません。MySQL の起動状態や DB_HOST / DB_PORT を確認します
- SQLSTATE[HY000] [1049] Unknown database: ログインはできたが DB_DATABASE の DB が存在しません
- ERROR 1698 Access denied for user 'root'@'localhost': Ubuntu などで root が auth_socket 認証になっているケースです