🤧

Docker の mysql コンテナに mysql コマンドで接続できない

に公開

はじめに

今回、Dcoker の mysql コンテナを起動している状態で、mysql コマンドで接続できませんでした。解決に時間がかかったため、内容を共有します。

環境

$ sw_vers
ProductName:		macOS
ProductVersion:		15.5
BuildVersion:		24F74

$ docker --version
Docker version 28.3.0, build 38b7060

$ docker compose version
Docker Compose version v2.38.1-desktop.1

$ mysql --version
mysql  Ver 9.3.0 for macos15.4 on arm64 (Homebrew)

状況

最初に、どのような状況だったのかを説明します。

mysql コンテナ

以下の docker-compose.ymlmy.cnf ファイルがあるとします。

docker-compose.yml
services:
  mysql:
    image: mysql:8.0
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - ./my.cnf:/etc/mysql/conf.d/my.cnf
    environment:
      MYSQL_ROOT_USER: root
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: sample
    ports:
      - "3306:3306"
my.cnf
[mysqld]
character-set-server=utf8mb4
character-set-client-handshake=FALSE
collation-server=utf8mb4_unicode_ci
ft_min_word_len=1
innodb_ft_min_token_size=1
innodb_ft_enable_stopword=0
ngram_token_size=1
default_authentication_plugin=mysql_native_password

[client]
default-character-set=utf8mb4

mysql コンテナを起動します。

$ docker compose up -d

[+] Running 2/2
 ✔ Network my-configs_default    Created
 ✔ Container my-configs-mysql-1  Started

$ docker compose ps
NAME                 IMAGE       COMMAND                  SERVICE   CREATED         STATUS         PORTS
my-configs-mysql-1   mysql:8.0   "docker-entrypoint.s…"   mysql     5 seconds ago   Up 4 seconds   0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp

無事に起動できていますね。

接続状況

mysql コマンドを使用し、mysql コンソールに接続してみましょう。

$ mysql -h 127.0.0.1 -u root -ppassword -P 3306 sample
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

エラーとなってしまいました。docker compose コマンドだとどうでしょうか?

$ docker compose exec mysql mysql -h 127.0.0.1 -u root -ppassword -P 3306 sample
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.42 MySQL Community Server - GPL

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sample             |
| sys                |
+--------------------+
5 rows in set (0.01 sec)

なんと、成功します。つまり、ローカルの mysql コマンドでは mysql に接続できず、Docker コンテナ内からは mysql に接続できるのです。ホスト名やユーザー名など、使用しているパラメータの値は同じです。いったいどういうことでしょうか?

原因

筆者の場合の原因は、ローカルで mysql サーバーを起動していたことでした。

$ brew services info mysql
mysql (homebrew.mxcl.mysql)
Running: ✔
Loaded: ✔
Schedulable: ✘
User: user
PID: 46630

これにより、ローカルの Docker コンテナではなく、ローカルの mysql サーバーに接続してしまっていました。そのため、docker compose コマンド経由ではコンテナ内の msyql への接続に成功し、mysql コマンド経由ではコンテナ内の myql への接続に失敗していました。

解決策

ローカルの mysql サーバーを停止しましょう。

$ brew services info mysql
mysql (homebrew.mxcl.mysql)
Running: ✘
Loaded: ✘
Schedulable: ✘

これで、ローカルからも mysql へ接続できるようになりました。

$ mysql -h 127.0.0.1 -P 3306 -u root -ppassword sample
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 8.0.42 MySQL Community Server - GPL

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sample             |
| sys                |
+--------------------+
5 rows in set (0.001 sec)

解説

ここから周辺情報を調べ、一体何が起こっていたのかを深掘りします。

いったい何が起こっていたのか?

元々は、ローカルから mysql に接続する必要性が生じ、以下のような状況でした。

$ docker compose ps
NAME                 IMAGE       COMMAND                  SERVICE   CREATED         STATUS         PORTS
my-configs-mysql-1   mysql:8.0   "docker-entrypoint.s…"   mysql     5 seconds ago   Up 4 seconds   0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp

$ mysql --version
zsh: command not found: mysql

$ which mysql
mysql: aliased to nocorrect mysql

そのため、brew install mysql で mysql をインストールしました。

$ brew install mysql
...
We've installed your MySQL database without a root password. To secure it run:
    mysql_secure_installation

MySQL is configured to only allow connections from localhost by default

To connect run:
    mysql -u root

To start mysql now and restart at login:
  brew services start mysql
Or, if you don't want/need a background service you can just run:
  /opt/homebrew/opt/mysql/bin/mysqld_safe --datadir\=/opt/homebrew/var/mysql

このとき、最後の brew services start mysql が目に留まり、そのまま実行していたのです。

$ brew services start mysql
==> Successfully started `mysql` (label: homebrew.mxcl.mysql)

これにより、ローカルで mysql サーバーが起動していました。

mysql サーバーを起動するとどうなるのか?

brew services info mysql はローカルに mysql サーバーを起動するコマンドでした。

mysql サーバーはデフォルトで以下の設定で起動します。

my.ini
[mysqld]
port=3306
bind-address=127.0.0.1

つまり、ポート 3306 が docker コンテナと mysql サーバーで競合していました。以下のコマンドからも確認できます。

$ sudo lsof -i:3306
COMMAND     PID  USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
com.docke  1991  user  168u  IPv6 0x1ed0be9b779fe32e      0t0  TCP *:mysql (LISTEN)
mysqld    56090  user   21u  IPv4 0xdd71e69fd3126c43      0t0  TCP localhost:mysql (LISTEN)

なぜ、ポート 3306 が競合しているにも関わらず、両方とも起動に成功しているのか?

ポートが競合するなら、後から起動したプロセスは実行に失敗するのでないでしょうか?

LLM に聞いたところ、異なるインターフェース(*localhost)にバインドされているため共存できるとのことでした。

プロセス バインドアドレス ポート 状態
com.docker.backend *(全インターフェース) 3306 LISTEN
mysqld(Homebrew) localhost(127.0.0.1) 3306 LISTEN

バインド先には IPv6 の *(全インターフェース)と IPv4 の localhost127.0.0.1)があります。

バインド先 説明
* (0.0.0.0) 全てのネットワークインターフェースにバインド(localhost 含む)。ホストの外部 IP でも接続できる。
127.0.0.1 ローカルループバック専用。外部からはアクセスできない。

実行した mysql コマンドでは、ホスト名に 127.0.0.1 を指定していました。そのため、ローカルで起動している mysql サーバーに接続してしまっていたのです。

どうすればよかったのか?

Dcoker コンテナで mysql を起動するなら、ローカルで mysql サーバーを起動することはないでしょう。mysql パッケージではなく、mysql-client パッケージのインストールで十分です。

$ brew uninstall mysql

$ brew install mysql-client

また、mysql-client には server コンポーネントが含まれていません。仮に mysql サーバーを起動しようとしてもエラーになります。

$ brew services start mysql
Error: Formula `mysql` is not installed.

終わりに

最初はネットワーク周りが原因であることに気づかず、コマンドの引数を試行錯誤して時間を浪費しました。どなたかのお役に立てましたら幸いです。

Discussion