ByteScope

3306

連接埠 3306 · MySQL

TCPIANA 有指派資料庫

MySQL、MariaDB、Percona 用來聽傳統用戶端協定的連接埠,也是驅動程式回報「連不上」時指的那一個。

查出是誰占用連接埠 3306

照你的系統挑一行貼上去執行。它會直接印出占著這個連接埠的行程,以及它綁在哪個位址上——通常看到這兩件事答案就出來了。

從機器外面確認一次

`nmap -Pn -p 3306 db.example.com` 從主機外面問了唯一重要的那個問題。`open` 代表有東西完成了 TCP 交握;`closed` 代表主機回了一個 reset,所以它連得到但沒有人在聽;`filtered` 代表什麼都沒回來,是防火牆或安全群組把封包丟掉而不是拒絕。加 `--reason` 可以看出實際是哪一種,加 `-sV` 則會讓 nmap 讀 MySQL 的交握並回報伺服器版本。只掃你自己負責的主機。

連不上 3306 的時候怎麼讀

你看到的訊息代表什麼
ERROR 2003 (HY000): Can't connect to MySQL server on 'db.example.com:3306' (111)errno 111 在 Linux 上是 `ECONNREFUSED`,在 macOS 上是 61:封包有送到那台主機,而核心回了 reset,因為沒有任何行程持有這個連接埠。可能是伺服器沒開、開機時就掛了,或是綁在一個不包含你撥過去那個位址的位置上。上面那些指令要在資料庫那台機器上跑,不是在用戶端。
The client hangs for tens of seconds, then reports (110) or a connect timeouterrno 110 是 `ETIMEDOUT`:完全沒有回應。有東西正在安靜地丟掉你的 SYN——雲端安全群組、主機上的防火牆,或是中間某段網路 ACL。被拒絕是立刻回來的,被丟掉才會慢。這段等待本身就是診斷結果。
[ERROR] Do you already have another mysqld server running on port: 3306 ? / bind: Address already in use`EADDRINUSE`:已經有東西占著這個 socket,而 mysqld 是在啟動途中就結束,不是啟動之後才掛。十次有九次是另一份裝在不同路徑的 MySQL 或 MariaDB,再不然就是某個容器把 3306 發布到主機上。動手砍之前先用上面的探測指令點名持有者;而如果過一兩分鐘連接埠自己就空出來,那是上一個伺服器留下的 socket 還停在 `TIME_WAIT`,根本沒有東西需要砍。
bind: Permission denied while starting the server on 3306這不是特權連接埠那條規則——那只管 1024 以下,而 3306 遠高於它。要看的是強制存取控制政策(SELinux 或 AppArmor)拒絕了那支執行檔的綁定、容器啟動時沒帶對應的能力,或是資料目錄的擁有者設定讓伺服器在碰到 socket 之前就先停住。在 Windows 上,同樣的樣貌出現在連接埠落在保留排除範圍裡的時候:沒有人在聽、也沒有人綁得起來,而且找不到任何 PID 可以怪。
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock'這件事跟 3306 完全無關。你寫了 `localhost`,所以用戶端改走 Unix domain socket,而它試的那個路徑不存在——通常是因為伺服器在容器裡,或是另一個套件把 socket 放在別的地方。要強制走 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 指派給 `mysql`,TCP 和 UDP 都有,但實務上只有 TCP 這半邊在用:上面跑的是傳統的 MySQL 用戶端/伺服器協定,從 JDBC、`mysqlclient` 到 `mysql2` 和 Go 的 `go-sql-driver`,每個驅動程式講的都是它。MariaDB 和 Percona Server 沿用同一個預設值,所以一台機器同時只能有一個占著 3306——這通常就是容器在已經裝了 Homebrew 或 XAMPP 版 MySQL 的機器上起不來的原因。MySQL 比較新的 X Protocol 走的是另一個號碼 33060,IANA 也把它另外登記成 `mysqlx`,所以 `netstat` 裡結尾是 33060 的那行不是你的連線。還有一個幾乎人人都會踩的細節:用官方用戶端函式庫時,主機名稱寫 `localhost` 並不等於 127.0.0.1。它會改走 Unix domain socket,連接埠整個被忽略,所以在 `localhost` 的連線上加 `-P 3306` 什麼也不會改變。真的要測這個連接埠,就寫 `127.0.0.1`,或是加上 `--protocol=TCP`。

連接埠 3306 該不該對外開

不要把 3306 對外開。連得到它的人就能一直試認證,而新出現的監聽幾個小時內就會被公開掃描器找到。TLS 也不是大家以為的那道保險:MySQL 8.0 第一次啟動會自己產一張自簽憑證,而用戶端預設的 `--ssl-mode=PREFERRED` 是「伺服器有就加密,沒有就安靜地用明文繼續」——它不驗證對方身分,所以中間有人插進來也看不出來。把伺服器綁在回送位址或內網位址上,然後用 `SHOW VARIABLES LIKE 'bind_address'` 確認它實際綁去哪:上游預設是 `*`,也就是每一張介面,但有些發行版套件會在自己的設定檔裡改成 127.0.0.1,兩種答案都不能用猜的。遠端資料庫請走 SSH 通道、VPN 或內網子網進去;真的非得可路由不可,至少在防火牆上限制來源位址,並且讓帳號帶上 `REQUIRE SSL`。

服務
MySQL
傳輸協定
TCP
登記狀態
IANA 有指派
分類
資料庫

站上可以搭配的工具

這些全都在你的瀏覽器裡跑,不會上傳任何東西。

相關連接埠

查 3306 的時候,通常也會順手看一下這幾個。

常見問題

明明就有東西在用,指令卻什麼都沒印出來?

幾乎都是權限問題。lsofss 會列出 socket,但別人的行程它不會顯示所有者,所以由系統帳號、容器執行環境或 launchd 啟動的服務,在你補上 sudo 之前就只是一個沒有主人的監聽項。Windows 則是反過來:netstat 什麼都沒有,綁定卻還是失敗,那代表這個號碼落在 Hyper-V、WSL2 或 Docker Desktop 開機時預留的範圍裡。

占著連接埠的那個行程可以直接砍掉嗎?

先看清楚它是什麼。沒收乾淨的開發伺服器砍掉沒事;正在寫入的資料庫不行,其他東西依賴的系統服務也不行。如果持有者是容器,請停容器,不要砍主機看到的那個行程——砍了執行環境只會把它拉起來。遇到真的不能動的,把自己的服務換一個連接埠反而更快。

為什麼本機連得到,別台機器就連不到?

因為它綁在 127.0.0.1 而不是 0.0.0.0。每一頁的指令之所以會把綁定位址跟行程名一起印出來,就是為了這件事:綁在回送位址上的服務,不管防火牆怎麼設,都只有這台機器自己連得到。現在不少框架是刻意這樣預設的,所以通常是一個參數的問題,不是 bug。如果已經是 0.0.0.0 還是不通,下一個要懷疑的就是主機防火牆或雲端的安全群組。

把服務換到冷門的連接埠會比較安全嗎?

幾乎沒有幫助。掃全網的機器持續在掃整段範圍,換號碼買到的是幾個小時,不是安全,代價卻是每個同事都得記住它。它確實能讓針對預設埠的無差別掃描少污染一點日誌,這算是實際但有限的好處。真正會改變結果的是認證、限制來源位址的防火牆,以及一開始就不要讓它對外。

連接埠 3306 還是卡住嗎?看完整的連接埠對照表,或是回到上面,從你實際看到的那行錯誤往回追。