MySQL 远程访问实战:从基础操作到真实踩坑记录

MySQL 远程访问实战:从基础操作到真实踩坑记录

本文记录了一次完整的 MySQL 远程连接踩坑过程,涵盖基础命令行操作、认证插件报错、IP 被拉黑等问题及解决方案。


一、MySQL 基础命令行操作

1.1 登录与退出

bash 复制代码
# 本地登录(默认走 localhost)
mysql -u root -p

# 指定 IP 登录(走网络连接)
mysql -h 192.168.1.100 -u root -p

# 指定端口
mysql -h 192.168.1.100 -P 3306 -u root -p

# 退出
exit;
-- 或
quit;

1.2 用户管理

sql 复制代码
-- 查看所有用户
SELECT User, Host, plugin FROM mysql.user;

-- 创建本地用户
CREATE USER 'alice'@'localhost' IDENTIFIED BY '密码';

-- 创建远程用户(允许任意 IP)
CREATE USER 'bob'@'%' IDENTIFIED BY '密码';

-- 创建远程用户(只允许特定 IP)
CREATE USER 'charlie'@'192.168.1.50' IDENTIFIED BY '密码';

-- 修改密码
ALTER USER 'bob'@'%' IDENTIFIED BY '新密码';

-- 删除用户
DROP USER 'bob'@'%';

-- 刷新权限(修改后必须执行)
FLUSH PRIVILEGES;

1.3 权限管理

sql 复制代码
-- 授予所有权限
GRANT ALL PRIVILEGES ON *.* TO 'bob'@'%';

-- 授予特定数据库权限
GRANT ALL PRIVILEGES ON mydb.* TO 'bob'@'%';

-- 授予只读权限
GRANT SELECT ON mydb.* TO 'readonly'@'%';

-- 撤销权限
REVOKE ALL PRIVILEGES ON *.* FROM 'bob'@'%';

-- 查看用户权限
SHOW GRANTS FOR 'bob'@'%';

1.4 数据库与表操作

sql 复制代码
-- 创建数据库
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 查看所有数据库
SHOW DATABASES;

-- 切换数据库
USE mydb;

-- 创建表
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100) UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 查看表结构
DESC users;
-- 或
SHOW CREATE TABLE users;

-- 插入数据
INSERT INTO users (name, email) VALUES ('张三', 'zhangsan@example.com');

-- 查询
SELECT * FROM users WHERE name LIKE '%张%';

-- 更新
UPDATE users SET email = 'new@example.com' WHERE id = 1;

-- 删除
DELETE FROM users WHERE id = 1;

1.5 服务管理(Linux)

bash 复制代码
# 启动
sudo systemctl start mysql

# 停止
sudo systemctl stop mysql

# 重启
sudo systemctl restart mysql

# 查看状态
sudo systemctl status mysql

二、远程访问配置

2.1 服务端配置

编辑 MySQL 配置文件:

  • Linux : /etc/mysql/mysql.conf.d/mysqld.cnf/etc/my.cnf
  • Windows : my.ini
ini 复制代码
# 允许所有网卡监听(默认 127.0.0.1 只监听本地)
bind-address = 0.0.0.0
# 或注释掉该行
# bind-address = 127.0.0.1

重启生效:

bash 复制代码
sudo systemctl restart mysql

2.2 防火墙放行

bash 复制代码
# UFW (Ubuntu/Debian)
sudo ufw allow 3306/tcp

# firewalld (CentOS/RHEL)
sudo firewall-cmd --permanent --add-port=3306/tcp
sudo firewall-cmd --reload

# 云服务器还需在安全组中放行 3306 端口

2.3 用户授权

sql 复制代码
-- 创建远程专用用户(推荐)
CREATE USER 'remote_user'@'%' IDENTIFIED BY '强密码';
GRANT ALL PRIVILEGES ON mydb.* TO 'remote_user'@'%';
FLUSH PRIVILEGES;

三、踩坑实录:认证插件与 IP 拉黑

3.1 环境背景

  • 服务端: MySQL 8.0(Linux 服务器)
  • 客户端: Windows C++ 程序,使用较老的 MySQL C API 库
  • 连接方式 : mysql_real_connect(conn, "10.136.11.246", "root", ...)

3.2 第一坑:IP 被拉黑

报错信息:

复制代码
mysql_real_connect failed: Host '10.136.26.183' is blocked because of many connection errors;
unblock with 'mysqladmin flush-hosts'

原因分析:

MySQL 有安全机制,当某个 IP 连续多次连接失败(默认阈值 100 次),会自动将该 IP 加入黑名单,防止暴力破解。

解决方法:

bash 复制代码
# 服务端执行,清空黑名单
mysqladmin flush-hosts

或登录 MySQL 后:

sql 复制代码
FLUSH HOSTS;

3.3 第二坑:认证插件不兼容

报错信息:

复制代码
mysql_real_connect failed: Authentication plugin 'caching_sha2_password' cannot be loaded: 找不到指定的模块。

原因分析:

MySQL 8.0 默认使用 caching_sha2_password 认证插件,但客户端(C++ 的 MySQL 库)版本太老,不支持这个插件。

根本区别:

MySQL 版本 默认认证插件 兼容性
5.7 及以前 mysql_native_password 老客户端都支持
8.0+ caching_sha2_password 需要新版客户端库

3.4 第三坑:ALTER USER 报错

报错信息:

复制代码
ERROR 1396 (HY000): Operation ALTER USER failed for 'root'@'10.136.11.246'

原因分析:

MySQL 的用户是 用户名 + Host 的组合。查询发现系统中只有:

sql 复制代码
SELECT User, Host FROM mysql.user;

结果:

复制代码
+------+-----------+
| User | Host      |
+------+-----------+
| root | %         |
| root | localhost |
+------+-----------+

'root'@'10.136.11.246' 这个用户根本不存在!

MySQL 用户匹配规则:

Host 值 含义
localhost 只允许本机 socket 连接
127.0.0.1 只允许本机 TCP 连接
192.168.1.% 允许该网段
10.136.11.246 只允许该特定 IP
% 允许任意 IP(最宽松)

注意localhost10.136.11.246

  • localhost127.0.0.1,不经过网卡
  • 10.136.11.246 是服务器的实际网卡 IP,走网络协议

四、完整解决过程

步骤 1:确认现有用户

sql 复制代码
SELECT User, Host, plugin FROM mysql.user WHERE User = 'root';

确认有 'root'@'%' 存在。

步骤 2:修改认证插件(服务端执行)

sql 复制代码
-- 修改已存在的 'root'@'%' 用户
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '你的密码';
FLUSH PRIVILEGES;

步骤 3:验证修改结果

sql 复制代码
SELECT User, Host, plugin FROM mysql.user WHERE User = 'root';

确认 'root'@'%'plugin 变为 mysql_native_password

步骤 4:清空 IP 黑名单

sql 复制代码
FLUSH HOSTS;

步骤 5:客户端连接测试

C++ 代码:

cpp 复制代码
#include <mysql.h>

MYSQL* conn = mysql_init(nullptr);
if (!mysql_real_connect(conn, 
                        "10.136.11.246",  // 服务器 IP
                        "root",           // 用户名
                        "你的密码",        // 密码
                        "数据库名",        // 数据库
                        3306,             // 端口
                        nullptr, 0)) {
    printf("连接失败: %s\n", mysql_error(conn));
} else {
    printf("连接成功!\n");
}
mysql_close(conn);

五、其他解决方案对比

方案 A:改服务端认证方式(本文采用)

优点 :客户端不用改,快速解决
缺点:安全性略降,新特性无法使用

sql 复制代码
-- 改单个用户
ALTER USER 'user'@'%' IDENTIFIED WITH mysql_native_password BY '密码';

-- 或改全局默认(my.cnf)
[mysqld]
default_authentication_plugin = mysql_native_password

方案 B:升级客户端库(推荐长期方案)

优点 :支持最新特性,更安全
缺点:需要重新编译项目

方案 C:使用 SSH 隧道(最安全)

bash 复制代码
# 本地建立隧道,把远程 3306 映射到本地 3307
ssh -L 3307:localhost:3306 user@服务器IP

# 然后 C++ 连接本地 3307,实际走的是加密 SSH
mysql_real_connect(conn, "127.0.0.1", "root", ..., 3307, ...);

优点 :不暴露 3306 端口,全程加密
缺点:需要额外配置 SSH


六、安全建议

  1. 不要用 root 远程访问:创建专用账号,最小权限原则
  2. 限制 Host 范围 :能用 192.168.1.% 就不要用 %
  3. 强密码 + SSL:生产环境必须配置 SSL 连接
  4. 修改默认端口:将 3306 改为其他端口,减少扫描
  5. fail2ban:自动封禁暴力破解 IP

七、常用排查命令速查

sql 复制代码
-- 查看当前连接
SHOW PROCESSLIST;

-- 查看连接错误阈值
SHOW VARIABLES LIKE 'max_connect_errors';

-- 修改阈值(临时)
SET GLOBAL max_connect_errors = 1000;

-- 查看用户认证方式
SELECT User, Host, plugin, authentication_string FROM mysql.user;

-- 查看被拉黑的 IP(performance_schema 需开启)
SELECT * FROM performance_schema.host_cache WHERE SUM_CONNECT_ERRORS > 0;

总结

问题 现象 解决
IP 被拉黑 Host is blocked FLUSH HOSTS;
认证插件不支持 caching_sha2_password cannot be loaded mysql_native_password 或升级客户端
用户不存在 Operation ALTER USER failed SELECT 查用户,确认 Host 正确
localhost vs IP 连接方式不同,匹配的用户不同 明确用 % 还是具体 IP

核心教训 :MySQL 的用户是 用户名@Host 的组合,修改前务必先查清楚!


本文基于 MySQL 8.0 + Windows C++ 客户端的真实踩坑经历整理。

相关推荐
他是龙5511 小时前
DVWA SQL 注入全级别通关笔记(Low / Medium / High / Impossible)
数据库·笔记·sql
qq_206901392 小时前
如何创建CDB公共用户_C##前缀强制规则与CONTAINER=ALL.txt
jvm·数据库·python
Hello World . .2 小时前
Linux驱动编程:内核同步的艺术-从互斥到底半部
linux·开发语言·数据库
Go 言 Go 语2 小时前
Claude Code 核心加载机制详解
服务器·前端·数据库
weixin_568996062 小时前
golang如何实现多活架构方案_golang多活架构方案实现教程
jvm·数据库·python
Absurd5872 小时前
Golang map遍历顺序为什么随机_Golang map遍历原理教程【进阶】
jvm·数据库·python
FinTech老王2 小时前
突破批处理瓶颈:KingbaseES并行DML技术如何榨干多核CPU性能
数据库·安全·oracle
2301_803875612 小时前
Golang怎么实现WebSocket房间_Golang如何按房间分组管理不同的连接群组【方法】
jvm·数据库·python
2301_796588502 小时前
Golang怎么用Task替代Makefile_Golang如何用go-task编写跨平台的任务脚本文件【教程】
jvm·数据库·python