Dockerで動かしているMySQLに作成したユーザーでPHPから接続できないときの対処方法

DockerでMySQLを使っていて、ユーザーを作成したのにそのユーザーで接続できないときの原因と対処方法です

作成したユーザーで接続できない問題

Dockerのコンテナで動作しているMySQLに任意のユーザーを作成し、そのユーザーでPHPプログラムから接続しようとしてもエラーとなる問題の対処方法です。

以下のようなエラーが発生する場合となります。

エラー:SQLSTATE[HY000] [1045] Access denied for user 'foouser'@'172.19.0.3' (using password: YES)

これは例えば以下のPHPプログラムを動かしたときにエラーとなるケースです。

<?php
$dsn = 'mysql:host=mysql;dbname=foodb;charset=utf8';
$user = 'foouser';
$password = 'password';
try {
  $db = new PDO($dsn, $user, $password,[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,]);
  $stmt = $db->prepare(
      "SELECT * FROM users ORDER BY birthday DESC"
  );
} catch (PDOException $e) {
  header('Content-Type: text/plain; charset=UTF-8', true, 500)
  exit($e->getMessage());
}
?>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<?php
    while ($row = $stmt->fetch()):
?>
<p>名前:<?php echo $row['name'] ?></p>
<p>誕生日:<?php echo $row['birthday'] ?></p>
<?php
    endwhile;
?>
</body>
</html>

ここでユーザーは「foouser」、パスワードは「password」です。

MySQLにrootではいって以下の作業でMySQLにこのユーザーを作成しています。

DockerのMySQLにrootで入る

$ docker exec -it docker-mysql bash
# mysql -u root -p

ユーザーの作成

GRANT ALL ON user_db.* to 'foouser'@'localhost' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;

エラーの発生する原因を結論からいうと、ユーザー作成時に’localhost’を指定しているからです。

Docker以外で構築されたLAMP環境(例えば:VMのLinux、XAMPP、MAMPなど)ではドメインのlocalhostでMySQLと接続できるためエラーは発生しません。

しかしDockerのMySQLは外部アプリなどからlocalhostで接続することができません。

上記のPHPプログラムの1行目にあるDSN(Data Source Name)を見てください。

‘mysql:host=mysql;dbname=foodb;charset=utf8’と書かれていますが、「host=mysql」となっています。

MySQLと接続するときに指定するhostはローカル環境だと一般的には「localhost」となります。

ですがDockerの場合はlocalhostでは接続できず、サービス名で接続する必要があります。

この場合、DockerのMySQLは「mysql」というサービス名で動作しているのでこのような記述となります。

サービス名で接続したあとでDockerではローカルアドレスを自動で割り振ります。

それが、エラーメッセージで表示されていた「172.19.0.3」です。

つまりlocalhost(172.0.0.1)では接続できないのです。

なのでデータベースにユーザーを作成するときにホスト名をlocalhostとすると上記エラーが発生してしまいます。

対処方法としては、データベースに作成するユーザーのホスト名をDockerが割り当てたIPにするか、’%’を指定するとエラーは解消されます。

ちなみ’%’は全てのホストという意味となります。

接続可能なユーザーの作成

GRANT ALL ON user_db.* to 'foouser'@'%' IDENTIFIED BY 'password'

作成済みのユーザーの情報を変更したい場合は、

RENAME USER 'foouser'@'localhost' to 'foouser'@'%';
FLUSH PRIVILEGES;

もしくは、phpMyAdminを使えるようにしていた場合は、ユーザーアカウントのページで対象ユーザーの「特権を編集」をクリックして変更できます。

DockerのMySQLとPHPの環境

参考にここで作成しているDockerのLAMP環境は、以下のDocker Composeを使っています。

【docker-compose.yml】

version: '3.7'

services:
mysql:
image: mysql:5.7
container_name: docker-mysql
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: 'password'

phpmyadmin:
container_name: docker-phpmyadmin
depends_on:
- mysql
image: phpmyadmin/phpmyadmin
environment:
PMA_HOST: mysql
restart: always
ports:
- "8080:80"

php-apache:
container_name: docker-php-apache
build: ./php
volumes:
- ./htdocs:/var/www/html
restart: always
ports:
- "80:80"
depends_on:
- mysql

volumes:
db_data: {}

【Dockerfile】

FROM php:7.3-apache
COPY ./php.ini /usr/local/etc/php/
RUN apt-get update \
&& apt-get install -y libfreetype6-dev libjpeg62-turbo-dev libpng-dev \
&& docker-php-ext-install pdo_mysql mysqli mbstring gd iconv

【php.ini】

[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

LAMP環境作成の詳細は以下の記事を参照してください。