MySQL/PostgreSQLへの接続エラー「Connection refused」を解決する
はじめに
開発中のアプリケーションからMySQLやPostgreSQLデータベースへ接続しようとした際に、Connection refused というエラーに遭遇することがある。これは、クライアントからサーバーへのTCP接続リクエストが、サーバー側のマシンによって拒否されたことを示すネットワークレベルのエラーである。
本記事は、この Connection refused エラーが発生した際の、原因切り分けと解決のためのトラブルシューティング手順をまとめた備忘録である。
対象環境
原因
Connection refused エラーの主な原因は、以下のいずれかであることが多い。
- データベースサーバーのプロセスが起動していない。
- クライアントが指定した接続先のホスト名(IPアドレス)またはポート番号が誤っている。
- データベースサーバーが、指定されたホストやポートで接続を待ち受けて(リッスンして)いない。例えば、
localhost(127.0.0.1) からの接続のみを許可している。 - OSやネットワーク機器、クラウドサービスのファイアウォールが、対象ポートへの通信をブロックしている。
解決策
原因を特定するため、クライアント側からサーバー側へ、ネットワーク層からアプリケーション層へと順を追って確認を進める。
ステップ1: クライアント側の接続情報を確認する
まず、アプリケーションやクライアントツールが使用している接続情報(ホスト名、IPアドレス、ポート番号)が正しいかを確認する。単純なタイプミスが原因であることも少なくない。
-
ホスト: 接続先のサーバーのホスト名またはIPアドレスが正しいか。
localhost、127.0.0.1、プライベートIP、パブリックIPなどを適切に使い分けているか。 -
ポート: データベースのデフォルトポートが正しいか。
- MySQL:
3306 - PostgreSQL:
5432
- MySQL:
ステップ2: サーバープロセスの稼働状況を確認する
次に、データベースサーバー上でプロセスが正常に起動しているかを確認する。
macOS / Linux
ps コマンドや systemctl (systemd採用のLinuxディストリビューション) を使用する。
ps aux | grep mysqld
ps aux | grep postgres
# または pg_ctl を使用
pg_ctl status -D /path/to/your/data/directory
sudo systemctl status mysql
sudo systemctl status postgresql
プロセスが存在しない場合は、サービスを起動する。
sudo systemctl start mysql
sudo systemctl start postgresql
Windows
PowerShellで Get-Service または tasklist を使用する。
Get-Service -Name "MySQL*"
Get-Service -Name "postgresql*"
tasklist | findstr "mysqld.exe"
tasklist | findstr "postgres.exe"
サービスが停止している場合は、「サービス」管理コンソール (services.msc) または以下のコマンドで起動する。
Start-Service -Name "MySQL84" # サービス名はバージョンにより異なる
Start-Service -Name "postgresql-x64-16" # サービス名はバージョンにより異なる
Docker
Dockerコンテナとして稼働させている場合は、docker ps でコンテナが起動しているか確認する。
docker ps
ステップ3: サーバーのリスニングポートを確認する
プロセスが起動していても、意図したネットワークインターフェースとポートでリッスンしていなければ接続できない。
macOS / Linux
ss コマンドまたは lsof コマンドを使用する。
ss -ltn | grep 3306
# または lsof
sudo lsof -i :3306
ss -ltn | grep 5432
# または lsof
sudo lsof -i :5432
出力結果の Listen 列に 0.0.0.0:3306 や *:3306 と表示されていれば、全てのネットワークインターフェースで接続を待ち受けている。127.0.0.1:3306 の場合は、ローカルホストからの接続のみ許可されている。
Windows
netstat コマンドを使用する。
netstat -ano | findstr "3306"
netstat -ano | findstr "5432"
状態が LISTENING となっていることを確認する。
ステップ4: ネットワークの疎通とポートの到達性を確認する
クライアントマシンからサーバーマシンへネットワーク的に到達可能かを確認する。
1. ping による疎通確認
まず、ICMPパケットが届くか ping で確認する。
ping db.example.com
ファイアウォールでICMPがブロックされている場合もあるため、ping が失敗しても接続できる可能性は残る。
2. telnet または nc によるポート接続確認
次に、目的のポートにTCP接続できるかを確認する。
telnet db.example.com 3306
接続に成功すると Connected to db.example.com. のようなメッセージが表示される。Connection refused が表示されれば、サーバーOSレベルで接続が拒否されていることが確定する。
ステップ5: データベース設定ファイルを確認する
ステップ3でローカルホスト (127.0.0.1) でしかリッスンしていないことが判明した場合、データベースの設定ファイルを変更して外部からの接続を許可する必要がある。
MySQL
設定ファイル (my.cnf または mysqld.cnf) 内の bind-address ディレクティブを確認する。ファイルの場所はOSやインストール方法によって異なる。
[mysqld]
# 127.0.0.1 に設定されているとローカルからしか接続できない
# bind-address = 127.0.0.1
# 0.0.0.0 に設定すると全てのネットワークインターフェースでリッスンする
bind-address = 0.0.0.0
PostgreSQL
postgresql.conf ファイルの listen_addresses ディレクティブを確認する。
# 'localhost' に設定されているとローカルからしか接続できない
# listen_addresses = 'localhost'
# '*' に設定すると全てのIPアドレスでリッスンする
listen_addresses = '*'
さらに、PostgreSQLでは pg_hba.conf ファイルでクライアントの認証方法を制御している。接続元IPアドレスからの接続を許可するルールが記述されているか確認する。
# TYPE DATABASE USER ADDRESS METHOD
# 例: 192.168.1.0/24 ネットワークからの全ユーザー・全DBへの接続を許可
host all all 192.168.1.0/24 scram-sha-256
ステップ6: ファイアウォールの設定を確認する
ここまでの手順で解決しない場合、ファイアウォールが原因である可能性が高い。サーバーOS、ネットワーク機器、クラウドプラットフォーム(AWSのセキュリティグループ、GCPのVPCファイアウォールルールなど)のファイアウォール設定を確認する。
Linux (ufw)
# ステータス確認
sudo ufw status
# ポートを許可するルールを追加
sudo ufw allow 3306/tcp # MySQL
sudo ufw allow 5432/tcp # PostgreSQL
# ufwをリロード
sudo ufw reload
Windows (Windows Defender ファイアウォール)
PowerShellで受信の規則を追加する。
# MySQL
New-NetFirewallRule -DisplayName "MySQL Server" -Direction Inbound -Protocol TCP -LocalPort 3306 -Action Allow
# PostgreSQL
New-NetFirewallRule -DisplayName "PostgreSQL Server" -Direction Inbound -Protocol TCP -LocalPort 5432 -Action Allow
クラウド環境
AWS EC2インスタンスであればセキュリティグループのインバウンドルール、GCP Compute EngineであればVPCファイアウォールルールで、クライアントのIPアドレスからデータベースのポート(3306 または 5432)へのTCP通信が許可されているかを確認する。
おわりに
Connection refused エラーは、単純な設定ミスからネットワークの問題まで、幅広い原因が考えられる。本記事で示したように、クライアントからサーバーへ、低レイヤーから高レイヤーへと順を追って切り分けを行うことが、迅速な問題解決の鍵となる。
この備忘録が、同様の問題に直面した開発者の助けとなれば幸いである。
Discussion