mysql连接失败应先验证host、port、database三者是否真实可达:ping检测ip连通性,telnet检查端口开放,mysql命令确认库存在;jdbc需将database作为url路径而非参数;pymysql的db参数不能为空;docker内不可用localhost连接宿主机mysql。

MySQL连接失败时,先检查host、port和database是否真实可达
绝大多数“Access denied”或“Connection refused”错误,根本不是权限或密码问题,而是连目标机器都没碰到。别急着改my.cnf或重置root密码,先确认三件事:IP能不能ping通、端口能不能telnet通、数据库名是不是真的存在。
常见错误现象:Can't connect to MySQL server on '192.168.1.100' (111)(拒绝连接)、Unknown database 'xxx'、Connection timed out。
-
ping 192.168.1.100—— 不通?查网络、防火墙、Docker容器是否暴露端口 -
telnet 192.168.1.100 3306—— 拒绝?确认MySQL是否监听0.0.0.0:3306(而非127.0.0.1:3306),检查bind-address配置 -
mysql -h 192.168.1.100 -P 3306 -u root -p -e "SHOW DATABASES;"—— 报Unknown database?说明连接成功了,但传入的database参数值写错了,不是服务器没启
Java JDBC连接串里database是路径不是参数,拼错就静默失败
JDBC URL格式是jdbc:mysql://host:port/database?param=value,其中database是URL路径段,不是查询参数。写成?database=xxx或漏掉它,会导致连接成功但后续执行SELECT时报No database selected。
使用场景:Spring Boot的spring.datasource.url、MyBatis原生配置、手动DriverManager.getConnection()。
- ✅ 正确:
jdbc:mysql://10.0.2.5:3306/myapp_prod?useSSL=false&serverTimezone=UTC - ❌ 错误:
jdbc:mysql://10.0.2.5:3306?database=myapp_prod&...(database被当成了参数,MySQL忽略) - ❌ 错误:
jdbc:mysql://10.0.2.5:3306/?useSSL=false(没指定库,后续SQL需显式USE myapp_prod,否则报错)
Python pymysql连接时db参数为空字符串,等同于没选库
pymysql的connect()函数接受db关键字参数,但它不支持空格、空字符串或None。传db=""或db=None,连接会建立,但默认库为空,所有表操作都必须带库名前缀,否则报Table 'xxx' doesn't exist。
性能影响:不指定db不会降低连接速度,但会让SQL变脆弱——比如SELECT * FROM users在未USE库时直接失败。
- ✅ 正确:
pymysql.connect(host='10.0.2.5', port=3306, user='app', password='x', db='myapp_prod') - ❌ 危险:
db=''或db=None—— 看似能连上,实际埋雷 - ⚠️ 注意:
db参数值必须与SHOW DATABASES输出完全一致,区分大小写(取决于MySQL服务器lower_case_table_names设置)
Docker环境里用localhost连MySQL,99%是错的
容器内程序访问宿主机MySQL,不能写localhost或127.0.0.1——那只会连自己(容器内部)的3306端口,而那里通常没MySQL。必须用宿主机真实IP,或Docker特殊DNS名host.docker.internal(macOS/Windows原生支持,Linux需加--add-host=host.docker.internal:host-gateway)。
常见错误现象:Connection refused,但docker exec -it app_container ping host.docker.internal能通,telnet host.docker.internal 3306却失败——说明MySQL没监听外部接口。
- 宿主机MySQL配置需含:
bind-address = 0.0.0.0(或至少包含宿主机IP) - 防火墙要放行3306,例如
ufw allow 3306 - Docker Compose中若MySQL也在容器里,应用应连服务名(如
mysql:3306),而非localhost
最容易被忽略的是:MySQL服务明明跑着,但bind-address默认是127.0.0.1,只响应本地回环请求。只要连接方不在同一进程空间(跨容器、跨机器、甚至WSL里连Windows上的MySQL),就必须改这个配置并重启服务。











