当前位置: 代码网 > it编程>数据库>Mysql > MySQL远程访问故障排查与解决方法

MySQL远程访问故障排查与解决方法

2026年08月24日 Mysql 我要评论
环境: docker mysql 8.4.11 on linux (ubuntu 22.04)容器名称: daily_test_mysql1. 问题概述1.1 问题描述在一个 docker 容器中运行

环境: docker mysql 8.4.11 on linux (ubuntu 22.04)
容器名称: daily_test_mysql

1. 问题概述

1.1 问题描述

在一个 docker 容器中运行 mysql 8.4.11 服务,本地(通过 127.0.0.1 或 unix socket)可以正常登录,但另一台远程服务器无法通过公网 ip 进行远程访问,始终返回 error 1045 (28000): access denied

1.2 环境信息

组件配置
数据库mysql 8.4.11 (docker 容器)
容器镜像mysql:8.4
宿主机内网 ip172.16.1.234/12
公网 ip103.236.97.252(通过云 nat 映射)
远程服务器 ip117.72.76.108
远程客户端mysql 8.0.46-0ubuntu0.22.04.3
初始端口映射容器 3306 → 宿主机 3308
最终端口映射容器 3306 → 宿主机 3309
容器数据卷/var/lib/docker/volumes/61a6d717.../_data

2. 排查流程

2.1 排查路线图

上图展示了从问题报告到最终解决的完整排查路径。关键转折点出现在 step 6(多维度连接对比测试)和 step 7(握手包分析),通过对比不同网络路径的连接结果,逐步排除了 mysql 配置、认证插件、防火墙等可能性,最终将问题锁定在云 nat 端口转发层面。

用户报告远程无法连接
       │
       ▼
┌─────────────────────────────────────┐
│  step 1: 容器状态与端口映射检查     │
│  - docker ps → 容器运行正常         │
│  - docker port → 3306→3308 映射正确 │
│  - ss -tlnp → docker-proxy 监听正常 │
└─────────────────────────────────────┘
       │
       ▼
┌─────────────────────────────────────┐
│  step 2: mysql 用户权限检查         │
│  - docker exec 进入容器             │
│  - 查询 mysql.user 表               │
│  → root@% 存在,允许远程连接        │
│  → admin@% 存在,允许远程连接       │
└─────────────────────────────────────┘
       │
       ▼
┌─────────────────────────────────────┐
│  step 3: mysql 网络配置检查         │
│  - bind_address = * ✅              │
│  - skip_networking = off ✅         │
│  - require_secure_transport = off   │
└─────────────────────────────────────┘
       │
       ▼
┌─────────────────────────────────────┐
│  step 4: 宿主机防火墙检查           │
│  - iptables input 策略 accept      │
│  - 无 drop 3308 规则               │
│  - 未启用 ufw/firewalld            │
└─────────────────────────────────────┘
       │
       ▼
┌─────────────────────────────────────┐
│  step 5: 认证插件兼容性排查         │
│  - mysql 8.4 默认 caching_sha2     │
│  - 改为 mysql_native_password      │
│  → 本地连接成功,远程仍失败         │
└─────────────────────────────────────┘
       │
       ▼
┌─────────────────────────────────────┐
│  step 6: 多维度连接测试             │
│  - 127.0.0.1:3306 → ✅ 成功        │
│  - 172.16.1.234:3308 → ✅ 成功     │
│  - 容器内 → 公网ip:3308 → ❌ 失败  │
│  - 远程服务器 → 公网ip:3308 → ❌   │
│  → 所有用户均失败(root,admin等)  │
└─────────────────────────────────────┘
       │
       ▼
┌─────────────────────────────────────┐
│  step 7: 网络层深入排查 ★关键发现★ │
│  - 抓取 mysql 握手包对比           │
│  → 公网ip:3308 → mysql 8.4.10     │
│  → 内网ip:3308 → mysql 8.4.11     │
│  → 这是两个不同的服务器!          │
└─────────────────────────────────────┘
       │
       ▼
┌─────────────────────────────────────┐
│  step 8: 端口变更与最终验证         │
│  - 申请新端口 3309 转发            │
│  - 创建新容器,映射 3309:3306      │
│  - 配置 mysql_native_password      │
│  - 放行云防火墙                    │
│  → 远程连接成功 ✅                 │
└─────────────────────────────────────┘

2.2 排查时间线

阶段操作结论
t1运行 docker ps 确认容器状态容器 daily_test_mysql 运行正常
t2查询 mysql.userroot@%admin@% 均存在
t3检查 bind_addressskip_networking配置正常,允许 tcp 远程连接
t4检查 iptables 规则防火墙未拦截 3308 端口
t5检查 authentication_policy默认仅允许 caching_sha2_password
t6启用 mysql_native_password 插件插件已激活,root@% 已切换
t7多维度连接对比测试内网 ip 成功,公网 ip 失败
t8抓取 mysql 握手包版本对比公网和内网指向不同 mysql 实例
t9确认云 nat 端口转发配置3308 端口被转发到其他机器
t10申请 3309 端口转发,重建容器最终连接成功

3. 各阶段详细分析

3.1 容器状态与端口映射检查

执行命令:

docker ps
docker port daily_test_mysql
ss -tlnp | grep 3308

结果分析:

  • 容器正常运行,状态为 up
  • 端口映射正确:3306/tcp → 0.0.0.0:3308
  • docker 用户态代理(docker-proxy)监听在 0.0.0.0:3308[::]:3308

结论: 容器层面无异常,端口映射配置正确。

3.2 mysql 用户权限检查

执行命令:

docker exec daily_test_mysql mysql -uroot -p123456 \
  -e "select user, host, plugin from mysql.user;"

结果:

user            host            plugin
root            %               caching_sha2_password
root            localhost       caching_sha2_password
admin           %               caching_sha2_password

分析:

  • root@% 中的 % 是通配符,匹配所有主机
  • admin@% 同样允许任意主机连接
  • 用户权限配置正确,理论上应允许远程连接

3.3 mysql 网络配置检查

检查项:

show variables like 'bind_address';       -- → * (监听所有接口)
show variables like 'skip_networking';    -- → off (允许tcp/ip)
show variables like 'require_secure_transport'; -- → off (不强制ssl)

结论: mysql 网络配置无异常,所有接口均开放 tcp 连接。

3.3.1 mysql 配置文件详解

mysql 的配置通过多个配置文件层级加载,优先级从低到高如下:

/etc/my.cnf                  # 全局配置(mysql 服务级别)
/etc/mysql/my.cnf            # 全局配置(mysql 发行版级别)
/etc/mysql/conf.d/*.cnf      # 附加配置目录(推荐放置自定义配置)
~/.my.cnf                    # 用户级别配置(仅影响该用户客户端)

在 docker 容器中,mysql:8.4 镜像自带的配置文件位于 /etc/mysql/ 目录下。自定义配置应放在 /etc/mysql/conf.d/ 目录下,以 .cnf 扩展名结尾。

配置文件结构

mysql 配置文件采用 ini 风格的节(section)结构:

[client]           # 客户端工具(mysql, mysqldump 等)的配置
port=3306
[mysql]            # mysql 命令行客户端的配置
prompt="\\u@\\h [\\d]> "
[mysqld]           # mysqld 服务器进程的配置 ← 这是最关键的节
bind-address=*
port=3306
max_connections=200

远程访问相关的核心配置项

配置项默认值说明远程访问要求
bind-address* (mysql 8.4)监听的网络接口必须设为 *0.0.0.0,不能是 127.0.0.1
skip-networkingoff是否禁用 tcp/ip必须为 off(注释掉或设为 0
port3306mysql 监听端口需与 docker 端口映射一致
require_secure_transportoff是否强制 ssl/tls可设为 off 允许非 ssl 连接
mysql_native_passwordon (mysql 8.4+)启用传统认证插件建议设为 on 兼容旧客户端
skip_name_resolveoff跳过 dns 反向解析建议设为 on 避免 dns 超时
max_connect_errors100最大连接错误次数可调大防止 ip 被锁定

正确和错误的配置对比

❌ 错误配置(导致只能本地连接):

[mysqld]
bind-address = 127.0.0.1    # 只监听本机,拒绝远程连接!
skip-networking = on         # 完全禁用 tcp/ip!

✅ 正确配置(允许远程连接):

[mysqld]
bind-address = *             # 监听所有网络接口
skip-networking = off        # 允许 tcp/ip 连接(默认值,可不写)
port = 3306                  # mysql 监听端口
mysql_native_password = on   # 启用传统认证插件(兼容旧客户端)
skip_name_resolve = on       # 跳过 dns 反向解析,避免连接卡顿

在 docker 容器中应用配置

方法一:通过 docker run 挂载配置目录(推荐)

# 1. 在宿主机创建配置文件
mkdir -p /root/mysql-conf
cat > /root/mysql-conf/my-custom.cnf << 'eof'
[mysqld]
mysql_native_password = on
skip_name_resolve = on
max_connect_errors = 1000
eof

# 2. 启动容器时挂载配置目录
docker run -d --name daily_test_mysql \
  -p 3309:3306 \
  -v /root/mysql-conf:/etc/mysql/conf.d \
  -e mysql_root_password=123456 \
  mysql:8.4

方法二:容器运行后复制配置文件(用于已有容器)

# 1. 创建配置文件
cat > /tmp/mysql_custom.cnf << 'eof'
[mysqld]
mysql_native_password = on
skip_name_resolve = on
eof

# 2. 复制到容器内
docker cp /tmp/mysql_custom.cnf daily_test_mysql:/etc/mysql/conf.d/

# 3. 重启容器
docker restart daily_test_mysql

方法三:通过 docker-compose.yml 管理(推荐生产环境)

version: '3.8'
services:
  mysql:
    image: mysql:8.4
    container_name: daily_test_mysql
    ports:
      - "3309:3306"
    environment:
      mysql_root_password: 123456
    volumes:
      - mysql_data:/var/lib/mysql
      - ./mysql-conf:/etc/mysql/conf.d
    restart: unless-stopped
volumes:
  mysql_data:

验证配置是否生效

# 查看配置文件是否被正确加载
docker exec daily_test_mysql mysql -uroot -p123456 \
  -e "show variables like 'mysql_native_password';"

# 输出应为 active
# variable_name          value
# mysql_native_password  on

排查配置文件常见问题

现象可能原因解决方法
配置不生效文件不在 /etc/mysql/conf.d/ 目录使用 docker cp 复制到正确位置
配置不生效文件名不是 .cnf 后缀确保文件名以 .cnf 结尾
配置不生效文件权限不正确设为 644chmod 644
容器启动失败配置语法错误检查 [mysqld] 节名拼写
配置被覆盖多个配置文件中相同项冲突后加载的配置会覆盖先加载的

3.4 认证插件兼容性分析

mysql 8.4 认证机制:

mysql 8.0 起默认认证插件从 mysql_native_password 变更为 caching_sha2_password,mysql 8.4 进一步将 mysql_native_password 标记为废弃(deprecated),默认不加载。

authentication_policy = *,   ← 表示仅允许 caching_sha2_password

影响:

  • 如果客户端(如旧版 php、python、java 连接器)不支持 caching_sha2_password,需要通过 --get-server-public-key 参数或 ssl 连接
  • mysql 8.0.46 客户端支持 caching_sha2_password,但需额外握手步骤

处理过程:

  1. 写入配置文件 /etc/mysql/conf.d/mysql_native.cnf 启用插件
  2. 重启容器使配置生效
  3. 执行 alter user 'root'@'%' identified with mysql_native_password by '123456'

注意: 即使切换了认证插件,本地连接(127.0.0.1)成功,但远程连接仍然失败——这说明问题不在认证插件本身。

3.5 多维度连接对比测试

这是排查过程中最关键的一步。通过对比不同连接路径的结果,可以精确判断问题出在哪个网络层面。

上图汇总了 5 组不同网络路径的连接测试结果。关键规律是:所有经过公网 ip 的路径全部失败,所有内网路径全部成功。这一对比强烈暗示问题不在 mysql 本身,而在公网到内网的网络转发层。

测试 1:容器内回环接口连接(验证 mysql 服务本身是否正常)

# 在容器内通过 127.0.0.1 连接 mysql(不经过 docker 端口映射)
docker exec daily_test_mysql mysql -u root -p123456 \
  -h 127.0.0.1 -p 3306 \
  -e "select current_user(), '连接成功' as status;"

输出:

current_user()  status
root@%          连接成功

结论: mysql 服务正常,root@% 用户密码正确,tcp 协议栈工作正常。

测试 2:宿主机内网 ip 连接(验证 docker 端口映射是否正常)

# 在容器内通过宿主机内网 ip 连接(经过 docker 端口映射 3308→3306)
docker exec daily_test_mysql mysql -u root -p123456 \
  -h 172.16.1.234 -p 3308 \
  -e "select '内网ip连接测试' as status;"

输出:

status
内网ip连接测试

结论: docker 端口映射正常,docker-proxy 正确转发连接。

测试 3:公网 ip 连接(验证云 nat 转发是否正常)

# 在容器内通过公网 ip 连接(经过云 nat → docker 端口映射)
docker exec daily_test_mysql mysql -u root -p123456 \
  -h 103.236.97.252 -p 3308 \
  -e "select '公网ip连接测试' as status;"

输出:

error 1045 (28000): access denied for user 'root'@'103.236.97.252' (using password: yes)

测试 4:其他用户也失败(排除密码错误可能性)

# 使用 admin 用户测试
docker exec daily_test_mysql mysql -u admin -p123456 \
  -h 103.236.97.252 -p 3308 \
  -e "select 'admin公网测试' as status;"

# 使用 testuser 用户测试
docker exec daily_test_mysql mysql -u testuser -ptest123 \
  -h 103.236.97.252 -p 3308 \
  -e "select 'testuser公网测试' as status;"

输出:

error 1045 (28000): access denied for user 'admin'@'103.236.97.252' (using password: yes)
error 1045 (28000): access denied for user 'testuser'@'103.236.97.252' (using password: yes)

关键推论: 所有用户、所有密码在公网 ip 路径下全部失败,这排除了密码错误、用户权限、认证插件等 mysql 层面的可能性。

测试 5:直连容器内部 ip(绕过 docker 代理,验证容器网络)

# 查看容器内网 ip
docker inspect daily_test_mysql | grep "ipaddress"
# 输出: "ipaddress": "192.168.0.2"

# 从宿主机直接连接容器内部 ip(不经过 docker-proxy)
docker run --rm --network host mysql:8.4 mysql -u root -p123456 \
  -h 192.168.0.2 -p 3306 \
  -e "select '直连容器' as status;"

输出:

status
直连容器

结论: 容器内部 mysql 服务完全正常,问题出在公网 ip 到本机的网络路径上。

测试结果汇总

测试编号连接路径命令结果
1容器内 → 127.0.0.1:3306mysql -h 127.0.0.1 -p 3306✅ 成功
2容器内 → 172.16.1.234:3308mysql -h 172.16.1.234 -p 3308✅ 成功
3容器内 → 103.236.97.252:3308mysql -h 103.236.97.252 -p 3308❌ 失败
4容器内 → 103.236.97.252:3308 (admin)mysql -u admin -h 103.236.97.252 -p 3308❌ 失败
5宿主机 → 192.168.0.2:3306mysql -h 192.168.0.2 -p 3306✅ 成功

关键发现:

  • 所有通过公网 ip 103.236.97.252:3308 的连接全部失败
  • 所有通过内网 ip(127.0.0.1172.16.1.234192.168.0.2)的连接全部成功
  • 失败和成功的路径唯一的区别是:公网 ip 的流量经过云 nat 网关
  • 这强烈暗示问题出在云 nat 的端口转发配置上

3.6 握手包分析(决定性证据)

这一步是最终找到根本原因的关键。通过解析 mysql 协议握手包,可以精确识别出对端 mysql 服务器的版本号,从而判断公网 ip 和内网 ip 是否指向同一个实例。

上图展示了从公网 ip 和内网 ip 分别抓取的 mysql 握手包对比。版本号 8.4.10 vs 8.4.11 的差异是决定性证据,证明公网和内网指向的是两台 完全不同的 mysql 服务器实例。

技术原理:mysql 握手包格式

mysql 客户端与服务器建立 tcp 连接后,服务器会首先发送一个握手包(handshake packet),其格式如下:

┌─────────────────────────────────────────────────┐
│ 包长度 (3 bytes)  |  序列号 (1 byte)              │
│ protocol version (1 byte)                        │
│ server version (null-terminated string)          │
│ connection id (4 bytes)                          │
│ auth plugin data part 1 (8 bytes)                │
│ filler (1 byte)                                  │
│ capability flags (2 bytes)                       │
│ character set (1 byte)                           │
│ status flags (2 bytes)                            │
│ capability flags (upper 2 bytes)                 │
│ ...                                              │
│ auth plugin name (null-terminated string)        │
└─────────────────────────────────────────────────┘

其中服务器版本字符串位于偏移量 5 字节处(第 5 个字节开始),以 null 字节(\x00)结尾。

执行命令

使用 python 脚本分别从公网 ip 和内网 ip 抓取 mysql 握手包:

# 测试 1:从公网 ip 103.236.97.252:3308 抓取握手包
python3 -c "
import socket
s = socket.socket()
s.settimeout(5)
s.connect(('103.236.97.252', 3308))
data = s.recv(1024)
s.close()
version = data[1:data.index(0, 1)].decode()
print(f'公网ip连接的mysql版本: {version}')
print(f'握手包前50字节(hex): {data[:50].hex()}')
"
# 测试 2:从内网 ip 172.16.1.234:3308 抓取握手包
python3 -c "
import socket
s = socket.socket()
s.settimeout(5)
s.connect(('172.16.1.234', 3308))
data = s.recv(1024)
s.close()
version = data[1:data.index(0, 1)].decode()
print(f'内网ip连接的mysql版本: {version}')
print(f'握手包前50字节(hex): {data[:50].hex()}')
"

原始输出

![[pasted image 20260819011659.png]]

公网ip连接的mysql版本: 8.4.10
握手包前50字节(hex): 4a0000000a382e342e31300069da00001c7f7c05524d5a7500ffffe00200ffdf15

内网ip连接的mysql版本: 8.4.11
握手包前50字节(hex): 4a0000000a382e342e313100280000000c52665a6d550c3000ffffff0200ffdf15

逐字节解析

公网 ip 握手包:4a0000000a382e342e313000...

位置字节(hex)含义
0-24a 00 00包长度(小端序)74 字节
300序列号0
40a协议版本10(mysql 协议 v10)
538版本字符串: ‘8’
62e版本字符串: ‘.’
734版本字符串: ‘4’
82e版本字符串: ‘.’
931版本字符串: ‘1’
1030版本字符串: ‘0’
1100null 终止符版本: “8.4.10”

内网 ip 握手包:4a0000000a382e342e313100...

位置字节(hex)含义
0-24a 00 00包长度(小端序)74 字节
300序列号0
40a协议版本10(mysql 协议 v10)
538版本字符串: ‘8’
62e版本字符串: ‘.’
734版本字符串: ‘4’
82e版本字符串: ‘.’
931版本字符串: ‘1’
1031版本字符串: ‘1’
1100null 终止符版本: “8.4.11”

关键差异对比

特性公网 103.236.97.252:3308内网 172.16.1.234:3308
mysql 版本8.4.108.4.11
版本字符串 hex38 2e 34 2e 31 30 0038 2e 34 2e 31 31 00
connection id69 da 00 00 (0xda69=55913)28 00 00 00 (0x28=40)
auth plugin data1c 7f 7c 05 52 4d 5a 750c 52 66 5a 6d 55 0c 30
capability flagsff ff e0 02ff ff 02 00

connection id 不同:公网和内网的 connection id 不同,说明是两次独立的 mysql 连接,而非同一连接的镜像。

auth plugin data 不同:认证数据(随机盐值)不同,说明是两台不同的 mysql 服务器实例。

版本号不同:8.4.10 和 8.4.11 是两个不同的发行版本,这证明了公网 ip 指向的是完全不同的 mysql 实例。

决定性结论

公网 ip 103.236.97.252:3308 指向的 mysql 服务器(8.4.10)与当前机器的 mysql 容器(8.4.11)不是同一个实例。

云 nat 网关将 3308 端口转发到了内网中另一台机器的 mysql 8.4.10 实例上。这就是为什么所有用户、所有密码都验证失败的根本原因——用户一直在连接别人的 mysql。

4. 根本原因分析

4.1 直接原因

云网络端口转发配置错误: 云平台 nat 网关将公网 ip 103.236.97.2523308 端口转发到了内网中另一台机器上运行的 mysql 8.4.10 实例,而不是用户当前所在的 172.16.1.234 机器。

4.2 技术原理

云 nat 端口转发机制

上图清晰展示了云 nat 网关的端口转发逻辑。3308 端口被错误地 dnat 到了内网另一台机器(172.16.x.x),而 3309 端口才正确映射到本机(172.16.1.234)。这是多租户云环境中端口分配冲突的典型场景。

远程服务器                    云平台 nat 网关               内部网络
117.72.76.108                     │                      172.16.0.0/12
       │                          │                           │
       │  ┌──────────────────────────────────────────┐        │
       ├──→ 103.236.97.252:3308                     │        │
       │  │  dnat 规则匹配                          │        │
       │  │  3308/tcp → 172.16.x.x:3308 (其他机器)  ├──→ ❌  │
       │  │  3309/tcp → 172.16.1.234:3309 (本机)    ├──→ ✅  │
       │  └──────────────────────────────────────────┘        │
       │                                                       │
       └──→ 103.236.97.252:3309 → 本机 → mysql 8.4.11 ✅

nat(network address translation)网关在云环境中负责将公网 ip 的端口映射到内网机器的对应端口。当多个内网机器需要暴露服务时,端口分配是互斥的——同一个端口不能被映射到两台不同的机器。

为什么之前会有"密码错误"的错觉

当远程服务器连接到 103.236.97.252:3308 时:

  1. 连接成功到达另一台机器的 mysql 8.4.10
  2. 该 mysql 的 root 密码不是 123456
  3. mysql 返回标准的 error 1045 (28000): access denied
  4. 用户误以为是自己的 mysql 配置有问题

这正是 access denied 作为通用错误码的迷惑性——它可能意味着密码错误,也可能意味着连接到了错误的服务器。

4.3 ssh 端口与 mysql 端口的关系

用户提到 ssh 使用 103.236.97.252:52704 登录,这表明:

  • 公网 ip 103.236.97.252 对应一个云 nat 网关
  • ssh 端口 52704 被映射到用户远程服务器的 ssh 服务
  • 不同端口可以映射到不同的内网机器
  • 这种多端口映射是多租户云环境的常见做法

5. 基础设施评估

5.1 物理机划分评估

评估结论: 不存在物理机划分不当的问题。

判断依据:

  1. 当前环境是云平台上的虚拟化环境,而非裸金属物理机划分
  2. 内网 ip 172.16.1.234/12 表明所有机器在同一个大二层网络内
  3. 云 nat 网关的端口转发是标准的多租户网络隔离方案
  4. 不同机器通过 nat 共享同一个公网 ip,各自暴露不同端口,这是合理的架构设计

5.2 资源配置评估

评估结论: 不存在明显的资源配置不足问题。

判断依据:

  1. mysql 容器运行正常,无 oom 或资源争抢现象
  2. docker 数据卷映射正常,磁盘 i/o 无异常
  3. 网络延迟在正常范围内(连接建立时间 < 5ms)
  4. 容器创建时间仅 41 分钟,处于初始运行阶段,资源使用量低

5.3 虚拟化实现缺陷评估

评估结论: 未发现虚拟化技术实现缺陷。

判断依据:

  1. docker 容器网络(bridge 模式)工作正常
  2. docker-proxy 正确转发 tcp 连接
  3. iptables dnat 规则正确:
dnat tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:3309 to:192.168.0.2:3306
  1. 内网 ip 直连容器成功,证明 docker 网络堆栈无异常
  2. 云 nat 网关的端口转发问题是配置层面(人为/策略)而非技术缺陷

5.4 根本原因归类

问题类别:配置错误(configuration error)
具体类型:云网络端口转发配置错误(cloud nat port forwarding misconfiguration)
严重程度:中(medium)
影响范围:仅影响公网远程访问,本地和内网访问不受影响

6. 解决方案与建议

6.1 已实施的解决方案

  1. 申请新端口转发:将公网 ip 103.236.97.2523309 端口转发到本机 172.16.1.234:3309
  2. 重建容器:删除旧容器,使用新端口映射创建新容器
docker run -d --name daily_test_mysql \
  -p 3309:3306 \
  -e mysql_root_password=123456 \
  mysql:8.4
  1. 配置认证插件:启用 mysql_native_password 插件并切换 root@% 认证方式
  2. 放行防火墙:在云平台安全组中添加入站规则,允许 tcp 3309 端口

6.2 长期建议

6.2.1 网络层面

  • 使用独立公网 ip:如果条件允许,为 mysql 服务申请独立的公网 ip,避免端口冲突
  • 端口规划:建立端口分配清单,记录每个端口映射的目标机器和服务,避免端口冲突
  • 监控 nat 规则:定期审计云 nat 网关的端口转发规则,确保配置正确

6.2.2 mysql 层面

  • 认证插件策略:mysql 8.4 已废弃 mysql_native_password,建议评估客户端兼容性,逐步迁移到 caching_sha2_password
  • ssl/tls 加密:启用强制 ssl 连接提供更高的安全性
  • 连接日志:开启 mysql 审计日志,记录所有连接尝试(包括失败的),便于快速定位问题

6.2.3 运维层面

  • 连接验证脚本:部署前执行自动化连接测试,验证从不同网络路径的访问
  • 文档化:维护网络拓扑和端口映射文档,类似本报告可作为参考

6.3 快速排查清单

未来遇到类似问题,可按以下顺序排查:

□ 1. docker ps / docker port → 确认容器和端口映射
□ 2. docker exec → 查询 mysql.user 表
□ 3. show variables → 检查 bind_address, skip_networking
□ 4. ss -tlnp / iptables → 检查防火墙
□ 5. 对比测试:内网 ip vs 公网 ip
□ 6. 抓取握手包:对比 mysql 版本号
□ 7. 检查云平台 nat 端口转发规则
□ 8. 检查云平台安全组/防火墙规则

7. 附录

7.1 关键命令速查

# 查看容器状态和端口映射
docker ps
docker port daily_test_mysql

# 查看 mysql 用户权限
docker exec daily_test_mysql mysql -uroot -p123456 \
  -e "select user, host, plugin from mysql.user;"

# 查看 mysql 配置
docker exec daily_test_mysql mysql -uroot -p123456 \
  -e "show variables like 'bind_address';"

# 查看端口监听状态
ss -tlnp | grep 3309

# 抓取 mysql 握手包
python3 -c "
import socket
s = socket.socket()
s.settimeout(5)
s.connect(('目标ip', 端口))
data = s.recv(1024)
s.close()
version = data[1:data.index(0, 1)].decode()
print(f'mysql版本: {version}')
"

# 测试端口连通性
curl -v telnet://103.236.97.252:3309 --connect-timeout 5

以上就是mysql远程访问故障排查与解决方法的详细内容,更多关于mysql远程访问故障的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com