3306
MySQL・MariaDB・Percona が従来のクライアントプロトコルを待ち受けるポート。ドライバが「届かない」と言ってくるのもここです。
自分の環境の行をそのまま実行してください。ポートを掴んでいるプロセス名と、バインドしているアドレスが出ます。たいていはそれだけで答えが分かります。
sudo lsof -nP -iTCP:3306 -sTCP:LISTEN`-n` はアドレスのホスト名解決を、`-P` は 3306 をサービス名に変えるのを止めるので、NAME の列は数値のまま読みやすく保たれます。`-iTCP:3306` でそのポートを選び、`-sTCP:LISTEN` で待ち受けソケットだけを残します。1 ソケットにつき 1 行で、COMMAND がプログラム、PID が手を出す番号、USER が起動したアカウント、NAME がバインドアドレスです。`127.0.0.1:3306` はループバックのみ、つまりこのマシンからは接続でき、他からは永遠に届きません。`*:3306` は全インターフェイスです。何も出ない(lsof は終了コード 1)なら誰も待ち受けていないので、接続拒否は妨害ではなく正直な返事です。`sudo` なしでは自分のプロセスしか見えないため、`_mysql` や Docker の中で動くサーバーは存在しないように見えます。COMMAND が `com.docker.backend` ならコンテナの公開ポートなので、その PID を kill するのではなくコンテナを停止してください。
sudo ss -tlnp 'sport = :3306'`-t` で TCP ソケット、`-l` で待ち受けソケットのみ、`-n` でサービス名の解決を止め、`-p` でソケットを使っているプロセスを出します。`sport = :3306` は ss の送信元ポートのフィルタ述語です。まず Local Address:Port の列を読んでください。`0.0.0.0:3306` は全 IPv4 インターフェイス、`127.0.0.1:3306` はループバックのみで、リモートのクライアントが永遠につながらない理由そのもの。`[::]:3306` は IPv6 のワイルドカードで、たいていの Linux では IPv4 も受けます。持ち主は最後の列に `users:(("mysqld",pid=1234,fd=25))` として出ます。引用符の中が名前、続くのが PID です。`ss` のないホストなら net-tools の書き方で `sudo netstat -tlnp | grep :3306`、`-p` はスラッシュ区切りの pid/program の組を出します。どちらも自分の所有でないプロセスを見るには特権が必要で、なければソケットは並ぶのにプロセスの列だけが空になります。
netstat -ano | findstr ":3306"`-a` ですべての接続とコンピューターが待ち受けているポートを表示し、`-n` でアドレスとポートを数値で表現し、`-o` で接続ごとのプロセス ID を含めます。PID は最後の列です。Local Address がバインド先で、`127.0.0.1:3306` はループバックのみ、`0.0.0.0:3306` は全インターフェイス。そしてその行がクライアント接続ではなくリスナーであるためには、State の列が LISTENING でなければなりません。PID をプログラムに変えるには `tasklist /FI "PID eq 1234"`、この PID フィルタは eq・ne・gt・lt・ge・le を受け付けます。絞り込みには注意してください。`findstr` は部分一致なので、`:3306` は MySQL の X Protocol ポートである `:33060` にも当たります。何かを kill する前に番号を最後まで読んでください。
Get-NetTCPConnection -LocalPort 3306 | Select-Object LocalAddress,LocalPort,State,OwningProcessPowerShell 版で、部分一致ではなくポートを厳密に一致させるところが、`netstat` の隣で打つ価値のある理由です。`State` が `Listen` で `LocalAddress` が `127.0.0.1` なら、それはローカルには応答して他の全員を拒む、まさにその構成です。`OwningProcess` の値を `Get-Process -Id` に渡せば実行ファイル名が分かります。結果が空ならそのポートは誰も持っていません。その状態でなお bind が失敗するなら、占有ではなく予約です。`netsh interface ipv4 show excludedportrange protocol=tcp` が、Hyper-V・WSL2・Docker Desktop が起動時に確保する帯を一覧します。
`nmap -Pn -p 3306 db.example.com` は、ホストの外側から見て本当に知りたい一点だけを尋ねます。`-Pn` はホスト探索を飛ばすので、ping を無視するマシンもスキャンされます。何が分かるかは nmap 自身の定義で決まります。`open` は対象上のアプリケーションがそのポートで待ち受けているということ。`closed` はホストは答えたがアプリケーションが待ち受けていないということで、到達はできるが何かが動いていないだけ。`filtered` はファイアウォールやフィルタ、その他のネットワーク上の障害物がポートを塞いでいて、nmap には開いているのか閉じているのか判断できないということです。`--reason` を足せばどのパケットがそれを決めたかが見えます。closed からの RST なのか、filtered で何も来なかったのか。`-sV` を付ければ MySQL のハンドシェイクを読んでサーバーバージョンまで報告します。スキャンは自分が責任を持つホストにだけ。
| 出ているもの | 意味 |
|---|---|
ERROR 2003 (HY000): Can't connect to MySQL server on 'db.example.com:3306' (111) | errno 111 は Linux の `ECONNREFUSED`、macOS では 61 です。パケットはホストに届き、そのポートを持つプロセスがないのでカーネルがリセットを返しました。サーバーが停止しているか、起動時に落ちたか、あなたが指定したアドレスを含まない場所にバインドしています。クライアント側ではなくデータベースのホストで自分の環境のコマンドを実行し、行があるかどうかではなくバインドアドレスを読んでください。 |
The client hangs for tens of seconds, then reports (110) or a connect timeout | errno 110 は `ETIMEDOUT`、つまり何も返ってきていません。パケットフィルタが SYN を黙って捨てています。クラウドのセキュリティグループ、ホスト上のファイアウォール、経路上のネットワーク ACL のいずれかです。拒否なら即座に返り、破棄なら遅い。この待ち時間そのものが診断結果です。外から `nmap --reason` で確かめれば、`filtered` が破棄、`closed` が拒否です。 |
[ERROR] Do you already have another mysqld server running on port: 3306 ? / bind: Address already in use | `EADDRINUSE` です。既に誰かがソケットを持っていて、mysqld は起動の途中で終了します。十中八九は別のインストールパスから来た二つ目の MySQL か MariaDB、あるいはホストに 3306 を公開しているコンテナです。何かを kill する前に上のコマンドで持ち主を名指ししてください。1、2 分待つとポートが勝手に空くなら、前のサーバーが `TIME_WAIT` のソケットを残しただけで、kill するものは最初から何もありません。 |
bind: Permission denied while starting the server on 3306 | 特権ポートの話ではありません。あれは 1024 未満だけの話で、3306 はずっと上です。見るべきは、そのバイナリの bind を拒んでいる強制アクセス制御(SELinux や AppArmor)、必要な capability なしで動いているコンテナ、あるいはソケットに辿り着く前にサーバーを止めているデータディレクトリの所有権です。Windows では同じ形が、ポートが予約された除外範囲に入っているときに現れます。誰も待ち受けておらず、誰も bind できず、責めるべき PID も存在しません。 |
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' | 3306 はそもそも関係していません。`localhost` を渡したのでクライアントは Unix ドメインソケットを使い、試したパスが存在しなかっただけです。サーバーがコンテナの中にあるか、別のパッケージがソケットを別の場所に置いているのが典型です。TCP を強制するなら `127.0.0.1`、あるいは `--socket` で実際のパスを指してください。 |
ERROR 1130 (HY000): Host '203.0.113.9' is not allowed to connect to this MySQL server | 朗報です。ポートもネットワークもサーバーも問題ありません。接続は MySQL がアカウントを引くところまで到達したうえで拒否されています。MySQL のアカウントは `ユーザー@ホスト` の組なので、`app@localhost` への権限は、同じユーザーが TCP で来たときには効きません。ネットワーク側に直すところはありません。 |
ERROR 1045 (28000): Access denied for user 'app'@'10.0.0.5' (using password: YES) | これもポートの問題ではありません。ハンドシェイクは完了し、認証が試みられて弾かれています。パスワードが違うか、クライアントが扱えない認証プラグインをアカウントが使っているかで、後者は古いドライバが MySQL 8 の `caching_sha2_password` に当たったときの定番です。 |
connect ECONNREFUSED 127.0.0.1:3306 from inside a container | コンテナの中の `127.0.0.1` は、そのコンテナ自身です。ホストでもデータベースのコンテナでもありません。Compose のサービス名で呼ぶか、ポートを公開してホストのアドレスを使ってください。ポート番号は合っていて、宛先が違います。 |
IANA は 3306 を TCP・UDP 両方で `mysql` に割り当てていますが、実際に使われるのは TCP だけです。ここを流れるのは従来型の MySQL クライアント/サーバープロトコルで、JDBC から `mysqlclient`、`mysql2`、Go の `go-sql-driver` まで、どのドライバもこれを話します。MariaDB も Percona Server も同じ既定を引き継いでいるので、1 台のマシンで 3306 を持てるのは一度に 1 つだけ。Homebrew や APT、XAMPP で入れた MySQL が動いている隣でデータベースのコンテナが起動しない、という話はたいていこれです。MySQL の新しい X Protocol は別の番号 33060 で、`mysqlx` として別に登録されているので、33060 で終わるソケットの行はあなたが追いかけている接続ではありません。そしてほぼ全員が一度は踏むのが、公式クライアントライブラリでのホスト名 `localhost` の扱いです。これは 127.0.0.1 を意味せず Unix ドメインソケットを選ぶので、ポート指定は丸ごと無視されます。`localhost` の接続に `-P 3306` を足しても何も変わりません。ポートそのものを試したいなら `127.0.0.1` と書くか、`--protocol=TCP` を渡してください。それから、読み込まれてすらいないかもしれない設定ファイルを眺めるより、動いているサーバー自身に `SHOW VARIABLES LIKE 'port'` と `SHOW VARIABLES LIKE 'bind_address'` で聞いてください。
3306 をインターネットに出さないでください。届いた相手は何度でも認証を試せますし、新しいリスナーは数時間で公開スキャナーに見つかります。TLS は思われているほどの安全網ではありません。クライアント既定の `--ssl-mode=PREFERRED` は、サーバーが対応していれば暗号化し、対応していなければ平文で続けます。しかも何も検証しないので、間に入られても気づけません。ループバックかプライベートアドレスにバインドし、実際にどうなったかは `SHOW VARIABLES LIKE 'bind_address'` で確認してください。上流の既定は全インターフェイスを意味する `*` ですが、いくつかのディストリビューションのパッケージは独自の設定でこれを上書きしているので、どちらも聞かずに決め打ちするのは危険です。リモートのデータベースへは SSH トンネル、VPN、プライベートサブネット越しに届かせるのが基本です。どうしても経路が必要ならファイアウォールで送信元を絞り、期待するのではなくアカウント側に TLS を必須にし、`user@'%'` の権限付与は定義上インターネット全体を受け入れるということを忘れないでください。
どれもブラウザ内で完結します。アップロードは発生しません。
3306 を調べているとき、ついでに確認することになりがちなポートです。
ほぼ権限の問題です。lsof や ss はソケット自体は出しますが、他ユーザーのプロセスは所有者の列を伏せるので、システムアカウントやコンテナランタイム、launchd が起動したサーバーは sudo を付け直すまで持ち主不明のリスナーに見えます。Windows は逆で、netstat には何も出ないのに bind だけ失敗します。これは Hyper-V や WSL2、Docker Desktop が起動時に予約したポート帯に当たっている状態です。
何なのかを先に見てください。取り残された開発サーバーなら問題ありませんが、書き込み中のデータベースは別ですし、他が依存しているシステムサービスも同様です。持ち主がコンテナならコンテナごと停止してください。ホストから見えるプロセスを kill してもランタイムが再起動するだけです。どうしても止められないものなら、自分のサービスを別のポートへ移すほうが早く片付きます。
0.0.0.0 ではなく 127.0.0.1 にバインドしているからです。各ページのコマンドがプロセス名と並べてバインド先アドレスを出しているのはこのためで、ループバックにバインドしたものはファイアウォールの設定に関係なく自分のマシンからしか届きません。最近は意図的にそれを既定にしているフレームワークも多いので、たいていはバグではなくフラグの問題です。すでに 0.0.0.0 なのに届かないなら、次に疑うのはホストのファイアウォールかクラウドのセキュリティグループです。
ほとんどなりません。インターネット全体を舐めるスキャナーはポート範囲を丸ごと走査し続けているので、稼げるのは数時間であって安全ではなく、代わりに関係者全員がその番号を覚える羽目になります。既定ポートを狙う無差別スキャンのログが減るという効果は確かにありますが、それだけです。結果を変えるのは認証と、送信元アドレスを絞ったファイアウォールと、そもそも外に出さないことです。
ポート 3306 でまだ詰まっていますか。ポート一覧をすべて見る。あるいは上に戻って、実際に出たエラー文から追ってください。