概要
Dockerを利用してローカルDBに接続するDjangoアプリケーションを起動後、DBeaver(データベース管理ツール)でローカルDBに接続したら以下のエラーが表示されました。
ERROR 1045 (28000): Access denied for user 'root'@'localhost'
本記事ではこちらの原因と解決方法を記載します。
解決方法
まずは結論から。
以下の箇所を変更することで、解決しました。
修正前
mysql:
image: mysql:latest
container_name: xxxxx
environment:
MYSQL_ROOT_PASSWORD: xxxxx
MYSQL_USER: root
MYSQL_PASSWORD: xxxxx
MYSQL_DATABASE: xxxxx
ports:
- "3306:3306"
上記の状態だとDBeaverの上述のエラーになります。
※ただし、上記でもDockerコンテナに入ってmysql -u root -p
でアクセスすると問題なく接続できます
修正後
mysql:
image: mysql:latest
container_name: xxxxx
environment:
MYSQL_ROOT_PASSWORD: xxxxx
MYSQL_USER: xxxxx
MYSQL_PASSWORD: xxxxx
MYSQL_DATABASE: xxxxx
ports:
- "3310:3306" # MySQLコンテナを3310にマッピング
上記の通り、ports
を変更することで、無事にDBeaverでローカルDBに入れました。
原因は...ポート番号の競合だった
原因はポート番号3306にありました。
なぜ3310に変更したら解決したのか?というと、3306ポートで競合が発生していたからです。
以下のコマンドで、3306が使われているのか確認できます。
sudo lsof -i :3306
lsof
コマンドは"List Open Files"
の略。
システム上で開かれているファイルやネットワークソケット、プロセスなどの情報をリストするためのコマンドです。これにより、ポート3306でリスンしているプロセスがわかります。
なにも返ってこない場合は3306ポートは使われていません。
しかし、自分の場合、以下のように返ってきました。
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mysqld 1490 XXXXXXXXXX 20u IPv4 XXXXXXXXXXXXXXXXXX 0t0 TCP localhost:mysql (LISTEN)
上記の出力結果から、プロセスmysqld
によってポート3306が使用されていることが分かります。
つまり、ローカルマシン(ホストマシン)のMySQLサーバーがポート3306でリスンしているので、他のアプリケーションが同じポートを使用しようとすると競合が発生する、ということです。
3306のままでもDockerのmysqlコンテナに入ればアクセスできたのは、Docker上では、独自に確保したポートに接続しており、競合するポートがなかったからですね。
MySQLコンテナをポート3310にマッピングした場合、MySQLサーバーはポート3310でリスンし、MySQLクライアントはポート3310を使用して接続します。
新しいMySQLコンテナをDockerで起動する際、ポート番号を3306から変更する必要があったのです。上記では3310としましたが、3306以外であればOKです。これにより、複数のMySQLインスタンスを同じホストで実行できるようになります。
補足:mysqld
ってなに??
mysqld
はMySQLデータベースサーバー(MySQLデーモン)の実行プロセスです。
デーモンとはUNIX系OSではバックグラウンドで動作するプロセスのことで、docker compose up -d
のときのd
と同じデーモンプロセスですね。
ちなみに以下コマンドで稼働しているかわかります。
$ mysqladmin ping -h 127.0.0.1
mysqld is alive