ByteScope

3306

ポート 3306 · MySQL

TCPIANA 割り当てありデータベース

MySQL・MariaDB・Percona が従来のクライアントプロトコルを待ち受けるポート。ドライバが「届かない」と言ってくるのもここです。

ポート 3306 を使っているプロセスを特定する

自分の環境の行をそのまま実行してください。ポートを掴んでいるプロセス名と、バインドしているアドレスが出ます。たいていはそれだけで答えが分かります。

外側から確かめる

`nmap -Pn -p 3306 db.example.com` は、ホストの外側から見て本当に知りたい一点だけを尋ねます。`-Pn` はホスト探索を飛ばすので、ping を無視するマシンもスキャンされます。何が分かるかは nmap 自身の定義で決まります。`open` は対象上のアプリケーションがそのポートで待ち受けているということ。`closed` はホストは答えたがアプリケーションが待ち受けていないということで、到達はできるが何かが動いていないだけ。`filtered` はファイアウォールやフィルタ、その他のネットワーク上の障害物がポートを塞いでいて、nmap には開いているのか閉じているのか判断できないということです。`--reason` を足せばどのパケットがそれを決めたかが見えます。closed からの RST なのか、filtered で何も来なかったのか。`-sV` を付ければ MySQL のハンドシェイクを読んでサーバーバージョンまで報告します。スキャンは自分が責任を持つホストにだけ。

3306 につながらないときの読み方

出ているもの意味
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 timeouterrno 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 のサービス名で呼ぶか、ポートを公開してホストのアドレスを使ってください。ポート番号は合っていて、宛先が違います。

ポート 3306 で動いているもの

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 を外部に開けてよいか

3306 をインターネットに出さないでください。届いた相手は何度でも認証を試せますし、新しいリスナーは数時間で公開スキャナーに見つかります。TLS は思われているほどの安全網ではありません。クライアント既定の `--ssl-mode=PREFERRED` は、サーバーが対応していれば暗号化し、対応していなければ平文で続けます。しかも何も検証しないので、間に入られても気づけません。ループバックかプライベートアドレスにバインドし、実際にどうなったかは `SHOW VARIABLES LIKE 'bind_address'` で確認してください。上流の既定は全インターフェイスを意味する `*` ですが、いくつかのディストリビューションのパッケージは独自の設定でこれを上書きしているので、どちらも聞かずに決め打ちするのは危険です。リモートのデータベースへは SSH トンネル、VPN、プライベートサブネット越しに届かせるのが基本です。どうしても経路が必要ならファイアウォールで送信元を絞り、期待するのではなくアカウント側に TLS を必須にし、`user@'%'` の権限付与は定義上インターネット全体を受け入れるということを忘れないでください。

サービス
MySQL
トランスポート
TCP
登録状況
IANA 割り当てあり
カテゴリ
データベース

このサイトのツール

どれもブラウザ内で完結します。アップロードは発生しません。

関連するポート

3306 を調べているとき、ついでに確認することになりがちなポートです。

よくある質問

明らかに使用中なのに、コマンドが何も表示しないのはなぜ?

ほぼ権限の問題です。lsofss はソケット自体は出しますが、他ユーザーのプロセスは所有者の列を伏せるので、システムアカウントやコンテナランタイム、launchd が起動したサーバーは sudo を付け直すまで持ち主不明のリスナーに見えます。Windows は逆で、netstat には何も出ないのに bind だけ失敗します。これは Hyper-V や WSL2、Docker Desktop が起動時に予約したポート帯に当たっている状態です。

ポートを掴んでいるプロセスは kill してよい?

何なのかを先に見てください。取り残された開発サーバーなら問題ありませんが、書き込み中のデータベースは別ですし、他が依存しているシステムサービスも同様です。持ち主がコンテナならコンテナごと停止してください。ホストから見えるプロセスを kill してもランタイムが再起動するだけです。どうしても止められないものなら、自分のサービスを別のポートへ移すほうが早く片付きます。

ローカルからは届くのに、別のマシンからは届かないのはなぜ?

0.0.0.0 ではなく 127.0.0.1 にバインドしているからです。各ページのコマンドがプロセス名と並べてバインド先アドレスを出しているのはこのためで、ループバックにバインドしたものはファイアウォールの設定に関係なく自分のマシンからしか届きません。最近は意図的にそれを既定にしているフレームワークも多いので、たいていはバグではなくフラグの問題です。すでに 0.0.0.0 なのに届かないなら、次に疑うのはホストのファイアウォールかクラウドのセキュリティグループです。

珍しいポート番号に移すと安全になる?

ほとんどなりません。インターネット全体を舐めるスキャナーはポート範囲を丸ごと走査し続けているので、稼げるのは数時間であって安全ではなく、代わりに関係者全員がその番号を覚える羽目になります。既定ポートを狙う無差別スキャンのログが減るという効果は確かにありますが、それだけです。結果を変えるのは認証と、送信元アドレスを絞ったファイアウォールと、そもそも外に出さないことです。

ポート 3306 でまだ詰まっていますか。ポート一覧をすべて見る。あるいは上に戻って、実際に出たエラー文から追ってください。