前言
最近開發中遇到一個問題,mysql在服務器本地可以登錄,但是遠程通過3306端口卻不可以。這個問題困擾了我一周之久,終於在今天解決了。在解決的過程中試了很多的方法,遂記錄下來,希望能給大家一些提示。
排查錯誤位置
客戶端方面
首先通過ping命令對服務器進行測試,如果ping不通,則是網絡的問題,本文中沒有涉及這類問題的解決。
如果能ping通,再測試端口有沒有問題。首先安裝telnet, telnet是windows系統自帶的,搜索"啟動或關閉Windows功能", 找telnet客戶端,勾選即可啟動。在cmd中輸入telnet {服務器IP} 3306, 如果不能正確連接,說明是端口設置的問題, 再試試22端口有沒有問題,如果也有問題,就是服務器整體的端口設置有問題,如果只有3306有問題,那么就是3306端口、mysql的設置問題,繼續往下測試。
服務器方面
針對只有3306端口不能連接的情況,有以下幾種解決方法:
1. 修改配置文件,開啟對其他ip地址的監聽
輸入命令netstat -ntpl |grep 3306 和 netstat -ntpl |grep 22, 查看端口的綁定情況
正確情況下應為以下輸出:

如果3306只綁定的本地端口,就會出現和上圖不一致的輸出。需要對其配置文件進行修改:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
打開配置文件, 找到bind-address開頭的一行,如果后面的ip地址是127.0.0.1,也就是服務器只會接收本地的連接請求,那么就需要改變此地址來指向外部的IP地址。例如,可以改為:
lc-messages-dir = /usr/share/mysql
skip-external-locking
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address = 0.0.0.0
如果你的mysql版本是MySQL 8+,那么mysqld.cnf中可能不會包含bind-address這一行,應該像下面所示方法進行添加:
[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
log-error = /var/log/mysql/error.log
bind-address = 0.0.0.0
修改完成后,保存並退出。重啟mysql服務sudo systemctl restart mysql,使得配置文件的修改得以生效。
接下來再次回到客戶端進行驗證,如果能夠telnet連接3306端口,說明配置成功,如果還是不能連接,進入下一步驟。
2. 關閉防火牆
Ubuntu默認的防火牆為ufw。防火牆的作用是管理網絡規則,默認情況下打開防火牆是更好的選擇, 但是這里為了排除debug時的影響,就先關閉一下。
查看防火牆狀態sudo ufw status, 如果顯示active, 就運行sudo ufw disable關閉。
3. 修改 iptables
iptables定義了網絡訪問規則,它工作在內核中,是一個網絡過濾器。
運行
sudo iptables -I INPUT -p tcp --dport 3306 -j ACCEPT
表示添加接收3306端口的規則。
-I INPUT將當前命令插入在filter鏈的第一位置。
-p tcp表示添加tcp協議的擴展。
--dport XX-XX:指定目標端口。
-j ACCEPT: 規定的動作,這里為接收。
完成后,保存修改的配置sudo iptables-save。
然后再次在客戶端用telnet進行測試,得到結果:

說明連接3306端口成功了。(忽略這里的亂碼)
