🌟

MySQL/PostgreSQLへの接続エラー「Connection refused」を解決する

に公開

はじめに

開発中のアプリケーションからMySQLやPostgreSQLデータベースへ接続しようとした際に、Connection refused というエラーに遭遇することがある。これは、クライアントからサーバーへのTCP接続リクエストが、サーバー側のマシンによって拒否されたことを示すネットワークレベルのエラーである。

本記事は、この Connection refused エラーが発生した際の、原因切り分けと解決のためのトラブルシューティング手順をまとめた備忘録である。

対象環境

原因

Connection refused エラーの主な原因は、以下のいずれかであることが多い。

  • データベースサーバーのプロセスが起動していない。
  • クライアントが指定した接続先のホスト名(IPアドレス)またはポート番号が誤っている。
  • データベースサーバーが、指定されたホストやポートで接続を待ち受けて(リッスンして)いない。例えば、localhost (127.0.0.1) からの接続のみを許可している。
  • OSやネットワーク機器、クラウドサービスのファイアウォールが、対象ポートへの通信をブロックしている。

解決策

原因を特定するため、クライアント側からサーバー側へ、ネットワーク層からアプリケーション層へと順を追って確認を進める。

ステップ1: クライアント側の接続情報を確認する

まず、アプリケーションやクライアントツールが使用している接続情報(ホスト名、IPアドレス、ポート番号)が正しいかを確認する。単純なタイプミスが原因であることも少なくない。

  • ホスト: 接続先のサーバーのホスト名またはIPアドレスが正しいか。localhost127.0.0.1、プライベートIP、パブリックIPなどを適切に使い分けているか。
  • ポート: データベースのデフォルトポートが正しいか。
    • MySQL: 3306
    • PostgreSQL: 5432

ステップ2: サーバープロセスの稼働状況を確認する

次に、データベースサーバー上でプロセスが正常に起動しているかを確認する。

macOS / Linux

ps コマンドや systemctl (systemd採用のLinuxディストリビューション) を使用する。

title=MySQLのプロセス確認
ps aux | grep mysqld
title=PostgreSQLのプロセス確認
ps aux | grep postgres
# または pg_ctl を使用
pg_ctl status -D /path/to/your/data/directory
title=systemdでのサービス状態確認
sudo systemctl status mysql
sudo systemctl status postgresql

プロセスが存在しない場合は、サービスを起動する。

title=systemdでのサービス起動
sudo systemctl start mysql
sudo systemctl start postgresql

Windows

PowerShellで Get-Service または tasklist を使用する。

title=サービスの確認
Get-Service -Name "MySQL*"
Get-Service -Name "postgresql*"
title=プロセスの確認
tasklist | findstr "mysqld.exe"
tasklist | findstr "postgres.exe"

サービスが停止している場合は、「サービス」管理コンソール (services.msc) または以下のコマンドで起動する。

title=サービスの起動
Start-Service -Name "MySQL84" # サービス名はバージョンにより異なる
Start-Service -Name "postgresql-x64-16" # サービス名はバージョンにより異なる

Docker

Dockerコンテナとして稼働させている場合は、docker ps でコンテナが起動しているか確認する。

title=Dockerコンテナの確認
docker ps

ステップ3: サーバーのリスニングポートを確認する

プロセスが起動していても、意図したネットワークインターフェースとポートでリッスンしていなければ接続できない。

macOS / Linux

ss コマンドまたは lsof コマンドを使用する。

title=MySQL (3306) のリスニング確認
ss -ltn | grep 3306
# または lsof
sudo lsof -i :3306
title=PostgreSQL (5432) のリスニング確認
ss -ltn | grep 5432
# または lsof
sudo lsof -i :5432

出力結果の Listen 列に 0.0.0.0:3306*:3306 と表示されていれば、全てのネットワークインターフェースで接続を待ち受けている。127.0.0.1:3306 の場合は、ローカルホストからの接続のみ許可されている。

Windows

netstat コマンドを使用する。

title=MySQL (3306) のリスニング確認
netstat -ano | findstr "3306"
title=PostgreSQL (5432) のリスニング確認
netstat -ano | findstr "5432"

状態が LISTENING となっていることを確認する。

ステップ4: ネットワークの疎通とポートの到達性を確認する

クライアントマシンからサーバーマシンへネットワーク的に到達可能かを確認する。

1. ping による疎通確認

まず、ICMPパケットが届くか ping で確認する。

title=pingコマンド
ping db.example.com

ファイアウォールでICMPがブロックされている場合もあるため、ping が失敗しても接続できる可能性は残る。

2. telnet または nc によるポート接続確認

次に、目的のポートにTCP接続できるかを確認する。

title=telnetによるポート確認
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やインストール方法によって異なる。

my.cnf
[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 ディレクティブを確認する。

postgresql.conf
# 'localhost' に設定されているとローカルからしか接続できない
# listen_addresses = 'localhost'

# '*' に設定すると全てのIPアドレスでリッスンする
listen_addresses = '*'

さらに、PostgreSQLでは pg_hba.conf ファイルでクライアントの認証方法を制御している。接続元IPアドレスからの接続を許可するルールが記述されているか確認する。

pg_hba.conf
# 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)

title=ufwのステータス確認とルール追加
# ステータス確認
sudo ufw status

# ポートを許可するルールを追加
sudo ufw allow 3306/tcp  # MySQL
sudo ufw allow 5432/tcp  # PostgreSQL

# ufwをリロード
sudo ufw reload

Windows (Windows Defender ファイアウォール)

PowerShellで受信の規則を追加する。

title=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