MariaDB 常用运维指令手册
MariaDB 常用运维指令手册
适用版本:MariaDB 10.11 / 11.4 LTS / 11.8 LTS / 12.3 LTS / 13.x(滚动) 约定:
#root 或 sudo,$普通用户,MariaDB [(none)]>客户端提示符,<xxx>为占位符。 差异标注:正文用> **与 MySQL 的差异**引用块标注易踩坑之处。 更新时间:2026-11
目录
- 版本与支持周期
- 下载地址与安装
- 服务启停与初始化
- 客户端连接与工具链
- 配置文件与参数
- 账号、认证与权限
- 库表与引擎
- 备份与恢复
- binlog 与闪回
- 主从复制
- Galera 集群
- 日志体系
- 性能诊断
- 空间与容量
- 升级与迁移
- 高频故障速查
- 危险命令与避坑清单
- 附录:巡检脚本与速查
1. 版本与支持周期
1.1 发布模型
MariaDB 采用"每年 1 个 LTS + 季度滚动版本":
| 类型 | 命名规则 | 支持期 |
|---|---|---|
| LTS | 每年 .3 版本(如 12.3) |
11.4 及更早 5 年;11.8 起 3 年社区二进制 |
| 滚动(Rolling) | 12.0、13.0、13.1 | 到下一个滚动版发布为止 |
| 版本 | GA 时间 | 社区 EOL | 状态(2026-11) |
|---|---|---|---|
| 10.6 | 2021-07 | 2026-07-06 | 已 EOL,末版 10.6.28 |
| 10.11 | 2023-02 | 2028-02-16 | 维护中(存量最多) |
| 11.4 | 2024-05 | 2029-05-29 | 维护中 |
| 11.8 | 2025-06 | 2028-06-04 | 维护中 |
| 12.3 | 2026-05-28 | 2029-06-12 | 当前 LTS 推荐 |
| 13.0 | 2026-05 | 2026-Q4 | 滚动版,尝鲜 |
| 13.1 | 2026-09 | 2027-Q1 | 滚动版 |
反直觉点:11.8 的 EOL(2028-06)早于 11.4(2029-05)。因为从 11.8 起社区二进制支持期从 5 年缩短到 3 年。选型时不要以为"版本号越大支持越久"。
1.2 与 MySQL 的定位差异
MariaDB 是 MySQL 5.5 的分支,2010 年后独立演进。到今天两者已经不是"兼容版本"关系,而是"高度相似但存在大量不兼容点"。
| 维度 | MariaDB | MySQL |
|---|---|---|
| 当前 LTS | 12.3 / 11.8 / 11.4 / 10.11 | 8.4 / 9.7 |
| 认证插件 | 默认 mysql_native_password,支持 unix_socket、ed25519、PAM |
默认 caching_sha2_password,8.4 起禁用 native |
| GTID 格式 | domain-server-seq |
uuid:transaction |
| 复制命令 | 仍用 CHANGE MASTER TO / SHOW SLAVE STATUS |
8.0.22+ 改 SOURCE / REPLICA |
| JSON | JSON 是 LONGTEXT 别名 + 校验 |
原生二进制 JSON 类型 |
| 集群方案 | Galera(wsrep) | InnoDB Cluster / Group Replication |
| 备份工具 | mariadb-backup |
XtraBackup(第三方)/ Clone |
| 闪回 | mariadb-binlog --flashback 原生支持 |
无,需第三方工具 |
核心提醒:应用层如果用了 MySQL 8 的特性(CTE 之外的窗口函数两边都有,但 JSON 函数、字符集默认值、
caching_sha2_password),从 MySQL 迁到 MariaDB 或反向迁移都不能只换驱动,必须做 SQL 兼容性回归。
1.3 版本识别
mariadb --version
mariadbd --version
mariadb-admin version
SELECT VERSION();
SELECT @@version_comment;
SHOW VARIABLES LIKE 'version%';
-- 10.11.18-MariaDB-log
2. 下载地址与安装
2.1 官方入口总表
| 用途 | 地址 |
|---|---|
| 下载总入口 | https://mariadb.org/download/ |
| 官方仓库配置脚本 | https://r.mariadb.com/downloads/mariadb_repo_setup |
| 文档 | https://mariadb.com/docs/ |
| Docker 镜像 | https://hub.docker.com/_/mariadb |
| Connector(各语言驱动) | https://mariadb.com/downloads/connectors/ |
| Galera 集群文档 | https://mariadb.com/docs/galera-cluster/ |
| 版本发布公告 | https://mariadb.org/blog/ |
| 安全公告 | https://mariadb.org/about/#security-policy |
国内镜像(同步 yum/apt 仓库):
https://mirrors.tuna.tsinghua.edu.cn/mariadb/
https://mirrors.aliyun.com/mariadb/
https://mirrors.ustc.edu.cn/mariadb/
2.2 官方仓库安装(推荐)
# 1) 自动配置仓库(会检测发行版并写入正确的 repo)
curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version="mariadb-12.3"
# 2) RHEL / Rocky / Alma
dnf install -y MariaDB-server MariaDB-client MariaDB-backup
# 3) Ubuntu / Debian
sudo apt update
sudo apt install -y mariadb-server mariadb-client mariadb-backup
# 4) 启动
systemctl enable --now mariadb
systemctl status mariadb
# 5) 安全初始化
mariadb-secure-installation
注意:发行版自带源里的
mariadb-server版本通常落后 1~2 个大版本(RHEL 9 是 10.5,Ubuntu 24.04 是 10.11)。要装 12.3 必须用官方仓库脚本,并先卸载系统自带包(注意会与mysql包冲突)。
2.3 二进制 tar.gz
wget https://archive.mariadb.org/mariadb-12.3.3/bintar-linux-systemd-x86_64/mariadb-12.3.3-linux-systemd-x86_64.tar.gz
tar -xzf mariadb-12.3.3-linux-systemd-x86_64.tar.gz -C /usr/local
ln -s /usr/local/mariadb-12.3.3-linux-systemd-x86_64 /usr/local/mysql
# 目录与用户
groupadd -r mysql && useradd -r -g mysql -s /bin/false mysql
mkdir -p /data/mariadb/{data,logs,binlog,tmp}
chown -R mysql:mysql /data/mariadb
# 初始化
/usr/local/mysql/scripts/mariadb-install-db \
--basedir=/usr/local/mysql \
--datadir=/data/mariadb/data \
--user=mysql
2.4 Docker
docker run -d --name mariadb123 \
--restart unless-stopped \
-p 3306:3306 \
-e MARIADB_ROOT_PASSWORD='Str0ng#Pass2026' \
-e MARIADB_DATABASE=appdb \
-e MARIADB_USER=app \
-e MARIADB_PASSWORD='App#2026' \
-e TZ=Asia/Shanghai \
-v /data/mariadb123/data:/var/lib/mysql \
-v /data/mariadb123/conf:/etc/mysql/conf.d \
mariadb:12.3
docker logs -f mariadb123
docker exec -it mariadb123 mariadb -uroot -p
2.5 安装后必做
# 1) 运行安全向导:设 root 密码、删匿名用户、禁 root 远程、删 test 库
mariadb-secure-installation
# 2) 确认版本与数据目录
mariadb -e "SELECT VERSION(); SHOW VARIABLES LIKE 'datadir';"
# 3) 确认字符集(MariaDB 默认可能是 latin1,务必改 utf8mb4)
mariadb -e "SHOW VARIABLES LIKE 'character_set_server'; SHOW VARIABLES LIKE 'collation_server';"
# 4) 确认认证插件
mariadb -e "SELECT user, host, plugin FROM mysql.user;"
与 MySQL 的差异:MariaDB 的 root 默认使用
unix_socket认证(本地 root 系统用户免密),这是与 MySQL 最大的初始体验差异。mariadb -uroot能以系统 root 直接进,但换成其他系统用户就进不去。容器与非 root 场景要显式改密码或调整插件。
3. 服务启停与初始化
3.1 systemd
systemctl start mariadb
systemctl stop mariadb
systemctl restart mariadb
systemctl reload mariadb # 重载配置(部分参数)
systemctl status mariadb
systemctl enable mariadb
journalctl -u mariadb -n 200 --no-pager
与 MySQL 的差异:服务名是
mariadb,不是mysqld。虽然很多发行版提供了mysqld.service的兼容别名,但脚本里写mariadb更稳。
3.2 初始化
# 标准初始化
mariadb-install-db --user=mysql --datadir=/data/mariadb/data \
--defaults-file=/etc/my.cnf
# 常用参数
mariadb-install-db --help
# --auth-root-authentication-method=normal 让 root 用密码而不是 unix_socket
# 以 normal 方式初始化(推荐给容器/自动化,root 用密码)
mariadb-install-db --user=mysql --datadir=/data/mariadb/data \
--auth-root-authentication-method=normal
3.3 启动参数
mariadbd --defaults-file=/etc/my.cnf --user=mysql
mariadbd --print-defaults
mariadbd --verbose --help | head -30
mariadbd --help --verbose | grep -A2 'Default options'
3.4 优雅关闭
mariadb-admin -uroot -p shutdown
systemctl stop mariadb
# 查看当前连接与事务
mariadb -e "SHOW PROCESSLIST;"
mariadb -e "SELECT * FROM information_schema.innodb_trx;"
危险:
kill -9 mariadbd会跳过 InnoDB 正常 shutdown,下次启动走崩溃恢复。数据一般安全,但恢复时间不可控。
3.5 多实例
# 每实例独立 datadir / port / socket / pid
mariadbd --defaults-file=/etc/my3307.cnf --user=mysql &
mariadbd --defaults-file=/etc/my3308.cnf --user=mysql &
# /etc/my3307.cnf 关键差异
[mysqld]
port=3307
socket=/data/mariadb3307/mysql.sock
datadir=/data/mariadb3307/data
pid-file=/data/mariadb3307/mariadbd.pid
4. 客户端连接与工具链
4.1 客户端命令对照(重要)
MariaDB 10.5 起把工具名从 mysql* 改为 mariadb*,同时保留 mysql* 的符号链接(未来会移除)。
| 旧名(MySQL 风格) | 新名(MariaDB 推荐) | 作用 |
|---|---|---|
mysql |
mariadb |
客户端 |
mysqladmin |
mariadb-admin |
管理命令 |
mysqldump |
mariadb-dump |
逻辑备份 |
mysqlbinlog |
mariadb-binlog |
解析 binlog |
mysqlimport |
mariadb-import |
导入文本 |
mysqlcheck |
mariadb-check |
表检查修复 |
mysql_upgrade |
mariadb-upgrade |
升级系统表 |
mysqld |
mariadbd |
服务端 |
mysql_secure_installation |
mariadb-secure-installation |
安全初始化 |
注意:写新脚本一律用
mariadb*前缀。虽然现在mysql*还能用,但官方已明确计划移除符号链接,届时老脚本会集体失效。
4.2 连接
mariadb -uroot -p
mariadb -uroot -p -h127.0.0.1 -P3306
mariadb -uapp -p -h10.0.0.11 -P3306 appdb
mariadb -uroot -p -S /data/mariadb/mysql.sock
mariadb -uroot -p -e "SELECT VERSION();"
mariadb -uroot -p appdb < init.sql
mariadb -uroot -p -N -B -e "SELECT 1"
mariadb --defaults-extra-file=/etc/my.cnf.d/client.cnf
# ~/.my.cnf
[client]
user=ops
password=Ops#2026
host=127.0.0.1
port=3306
default-character-set=utf8mb4
chmod 600 ~/.my.cnf
4.3 交互式命令
MariaDB [(none)]> SHOW DATABASES;
MariaDB [(none)]> USE appdb;
MariaDB [appdb]> SHOW TABLES;
MariaDB [appdb]> DESC orders;
MariaDB [appdb]> SHOW CREATE TABLE orders\G
MariaDB [appdb]> SHOW PROCESSLIST;
MariaDB [appdb]> SHOW ENGINE INNODB STATUS\G
MariaDB [appdb]> SELECT @@version, @@version_comment;
MariaDB [appdb]> status;
MariaDB [appdb]> tee /tmp/session.log;
MariaDB [appdb]> source /tmp/script.sql;
MariaDB [appdb]> quit;
4.4 状态与连通性
mariadb-admin -uroot -p ping
mariadb-admin -uroot -p status
mariadb-admin -uroot -p processlist
mariadb-admin -uroot -p extended-status | head -40
mariadb-admin -uroot -p variables | grep -E 'max_connections|buffer_pool'
mariadb-admin -uroot -p kill <id>
mariadb-admin -uroot -p flush-logs
mariadb-admin -uroot -p flush-hosts
mariadb-admin -uroot -p shutdown
5. 配置文件与参数
5.1 文件位置与读取顺序
mariadbd --help --verbose | grep -A1 'Default options'
典型顺序:
/etc/my.cnf → /etc/my.cnf.d/*.cnf → ~/.my.cnf
RHEL 包默认拆分为 /etc/my.cnf.d/ 下的多个文件(server.cnf、client.cnf、galera.cnf 等)。Debian 系在 /etc/mysql/mariadb.conf.d/。
ls /etc/my.cnf.d/
mariadb -e "SHOW VARIABLES LIKE 'datadir'; SHOW VARIABLES LIKE 'socket';"
5.2 参数查看与修改
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW GLOBAL VARIABLES LIKE '%timeout%';
SHOW SESSION VARIABLES LIKE 'sql_mode';
SELECT @@global.max_connections, @@session.sql_mode;
SET GLOBAL max_connections = 2000;
SET GLOBAL slow_query_log = ON;
SET SESSION sql_mode = 'STRICT_TRANS_TABLES';
SET PERSIST max_connections = 2000; -- 10.4+ 支持持久化
RESET PERSIST max_connections;
与 MySQL 的差异:MariaDB 10.4 起才支持
SET PERSIST(MySQL 是 8.0 起)。持久化写入datadir/mysqld-auto.cnf,格式与 MySQL 不同,不要跨产品直接拷贝这个文件。
5.3 生产必调参数
| 参数 | 建议 | 说明 |
|---|---|---|
innodb_buffer_pool_size |
物理内存 50%~70% | 最大性能杠杆 |
innodb_buffer_pool_instances |
≥8G 时设 8 | |
innodb_log_file_size |
1~4G | MariaDB 仍用这个参数(不是 MySQL 8 的 innodb_redo_log_capacity) |
innodb_flush_log_at_trx_commit |
1(安全)/ 2(快) | |
sync_binlog |
1 | |
max_connections |
500~3000 | 配合连接池 |
character_set_server |
utf8mb4 | MariaDB 默认常是 latin1,必须显式设 |
collation_server |
utf8mb4_general_ci | MariaDB 没有 utf8mb4_0900_ai_ci(MySQL 8 专有) |
sql_mode |
STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
MariaDB 默认较宽松 |
binlog_expire_logs_seconds |
604800 | 10.6+ 支持;老版本用 expire_logs_days |
max_statement_time |
0(不限)或按需 | 超时杀查询,MariaDB 独有 |
innodb_snapshot_isolation |
12.3 起默认 ON | 升级前需测试一致性行为变化 |
与 MySQL 的差异:MariaDB 没有
utf8mb4_0900_ai_ci排序规则,也没有innodb_redo_log_capacity。从 MySQL 8 迁过来时这两个配置会直接报错。
5.4 配置模板(12.3 生产参考)
# /etc/my.cnf.d/server.cnf
[mysqld]
user=mysql
port=3306
datadir=/data/mariadb/data
socket=/data/mariadb/mysql.sock
pid-file=/data/mariadb/mariadbd.pid
tmpdir=/data/mariadb/tmp
bind-address=0.0.0.0
max_connections=2000
max_connect_errors=10000
wait_timeout=600
interactive_timeout=600
skip_name_resolve=ON
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
skip-character-set-client-handshake
innodb_buffer_pool_size=32G
innodb_buffer_pool_instances=8
innodb_log_file_size=2G
innodb_log_files_in_group=2
innodb_flush_log_at_trx_commit=1
innodb_flush_method=O_DIRECT
innodb_io_capacity=2000
innodb_io_capacity_max=4000
innodb_file_per_table=ON
innodb_print_all_deadlocks=ON
log-error=/data/mariadb/logs/error.log
slow_query_log=ON
slow_query_log_file=/data/mariadb/logs/slow.log
long_query_time=1
log_slow_admin_statements=ON
log_bin=/data/mariadb/binlog/mariadb-bin
binlog_format=ROW
binlog_expire_logs_seconds=604800
max_binlog_size=1G
sync_binlog=1
server-id=1
log_slave_updates=ON
default-time-zone='+08:00'
[client]
socket=/data/mariadb/mysql.sock
default-character-set=utf8mb4
6. 账号、认证与权限
6.1 认证插件(差异最大处)
-- 查看
SELECT user, host, plugin FROM mysql.user;
-- MariaDB 默认 mysql_native_password
CREATE USER 'app'@'10.0.0.%' IDENTIFIED BY 'App#2026';
-- unix_socket:系统用户与数据库用户同名即可免密(默认 root 就是这种)
CREATE USER 'root'@'localhost' IDENTIFIED VIA unix_socket;
CREATE USER 'ops'@'localhost' IDENTIFIED VIA unix_socket;
-- ed25519:更安全的密码认证(需插件)
INSTALL SONAME 'auth_ed25519';
CREATE USER 'sec'@'%' IDENTIFIED VIA ed25519 USING PASSWORD('Sec#2026');
-- PAM:接系统认证
INSTALL SONAME 'auth_pam';
CREATE USER 'pamuser'@'%' IDENTIFIED VIA pam USING 'mariadb';
-- 改密码
SET PASSWORD FOR 'app'@'10.0.0.%' = PASSWORD('New#2026');
ALTER USER 'app'@'10.0.0.%' IDENTIFIED BY 'New#2026';
与 MySQL 的差异:MariaDB 没有
caching_sha2_password,也不会在 8.4/9.x 里禁用 native 插件。从 MySQL 8 迁移过来时,MySQL 的caching_sha2_password用户导到 MariaDB 会直接不可用,必须重建为mysql_native_password或ed25519。
6.2 用户管理
CREATE USER 'app'@'10.0.0.%' IDENTIFIED BY 'App#2026';
ALTER USER 'app'@'10.0.0.%' IDENTIFIED BY 'New#2026';
ALTER USER 'app'@'10.0.0.%' ACCOUNT LOCK;
ALTER USER 'app'@'10.0.0.%' ACCOUNT UNLOCK;
DROP USER 'app'@'10.0.0.%';
RENAME USER 'app'@'10.0.0.%' TO 'app'@'10.0.1.%';
与 MySQL 的差异:MariaDB 仍然支持
GRANT ... IDENTIFIED BY ...隐式建用户(MySQL 8.0 已移除)。但为了可移植性,建议统一用CREATE USER+GRANT两步写法。
6.3 权限
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'app'@'10.0.0.%';
GRANT SELECT ON appdb.orders TO 'report'@'%';
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'monitor'@'%';
GRANT ALL PRIVILEGES ON appdb.* TO 'dba'@'10.0.0.%';
REVOKE DELETE ON appdb.* FROM 'app'@'10.0.0.%';
SHOW GRANTS FOR 'app'@'10.0.0.%';
SHOW GRANTS FOR CURRENT_USER();
FLUSH PRIVILEGES;
MariaDB 特有的权限:
| 权限 | 用途 |
|---|---|
BINLOG MONITOR |
10.5+ 替代 REPLICATION CLIENT |
REPLICA MONITOR |
10.5+ 替代 REPLICATION SLAVE |
SET USER |
切换会话身份(配合代理认证) |
DELETE HISTORY |
系统版本化表清理(10.3+) |
6.4 角色(10.0.5+)
CREATE ROLE role_read;
GRANT SELECT ON appdb.* TO role_read;
GRANT role_read TO 'report'@'%';
SET DEFAULT ROLE role_read FOR 'report'@'%';
SET ROLE role_read;
SHOW GRANTS FOR 'report'@'%';
6.5 安全基线
bind-address=10.0.0.11
local_infile=OFF
skip_name_resolve=ON
-- 删匿名用户与测试库
DELETE FROM mysql.user WHERE user='';
DROP DATABASE IF EXISTS test;
FLUSH PRIVILEGES;
-- 确认没有空密码账号
SELECT user, host, password, plugin FROM mysql.user
WHERE password='' AND plugin NOT IN ('unix_socket');
7. 库表与引擎
7.1 库操作
CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE DATABASE IF NOT EXISTS appdb;
DROP DATABASE appdb; -- 危险
ALTER DATABASE appdb CHARACTER SET utf8mb4;
SHOW DATABASES;
SHOW CREATE DATABASE appdb;
7.2 存储引擎(比 MySQL 丰富)
SHOW ENGINES;
SHOW TABLE STATUS LIKE 'orders'\G
SELECT table_name, engine FROM information_schema.tables WHERE table_schema='appdb';
| 引擎 | 说明 |
|---|---|
| InnoDB | 默认,事务、行锁、崩溃恢复 |
| Aria | MyISAM 的改进版,崩溃安全,用于系统表与临时表 |
| MyISAM | 老引擎,表锁,无事务 |
| ColumnStore | 列式,分析型(需单独部署) |
| Spider | 分片/联邦,跨实例透明查询 |
| S3 | 把表存到 S3(11.2+) |
| MEMORY | 内存表 |
| CONNECT | 访问外部文件/数据源 |
-- 改引擎
ALTER TABLE orders ENGINE=InnoDB;
ALTER TABLE logs ENGINE=Aria;
与 MySQL 的差异:MariaDB 保留并增强了 MyISAM/Aria,还提供 ColumnStore、Spider、S3 等引擎;MySQL 8 已基本只支持 InnoDB。反过来,MariaDB 没有 MySQL 的
TempTable引擎。
7.3 表操作与 MariaDB 特有语法
CREATE TABLE orders (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
user_id BIGINT UNSIGNED NOT NULL,
amount DECIMAL(12,2) NOT NULL DEFAULT 0,
status TINYINT NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY idx_user_created (user_id, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE orders ADD COLUMN remark VARCHAR(255);
ALTER TABLE orders ADD INDEX idx_status (status), ALGORITHM=INPLACE, LOCK=NONE;
TRUNCATE TABLE orders; -- 危险
DROP TABLE orders; -- 危险
MariaDB 独有或增强的语法:
-- 1) INSERT / DELETE / UPDATE ... RETURNING(10.5+ 完善)
INSERT INTO orders (user_id, amount) VALUES (100, 9.9) RETURNING id, created_at;
DELETE FROM orders WHERE status=0 LIMIT 1000 RETURNING id;
UPDATE orders SET status=1 WHERE id=1 RETURNING id, status;
-- 2) 序列(SEQUENCE,跨引擎可用,替代 AUTO_INCREMENT 的部分场景)
CREATE SEQUENCE seq_order_id START WITH 1000 INCREMENT BY 1;
SELECT NEXT VALUE FOR seq_order_id;
SELECT NEXTVAL(seq_order_id);
DROP SEQUENCE seq_order_id;
-- 3) 系统版本化表(保留每行历史版本,审计场景)
CREATE TABLE contracts (
id INT PRIMARY KEY,
amount DECIMAL(12,2),
row_start TIMESTAMP(6) GENERATED ALWAYS AS ROW START,
row_end TIMESTAMP(6) GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (row_start, row_end)
) WITH SYSTEM VERSIONING;
SELECT * FROM contracts FOR SYSTEM_TIME AS OF '2026-11-01 00:00:00';
-- 4) 语句级超时(防止单条 SQL 拖死实例)
SET STATEMENT max_statement_time=5 FOR SELECT * FROM big_table;
-- 5) 动态列(BLOB 内存 JSON 访问)
CREATE TABLE events (id INT PRIMARY KEY, data BLOB);
INSERT INTO events VALUES (1, COLUMN_CREATE('user', 'u1', 'action', 'login'));
SELECT COLUMN_GET(data, 'action' AS CHAR) FROM events;
-- 6) 表值构造器与 CTE(10.2+ 支持递归 CTE)
WITH RECURSIVE seq AS (
SELECT 1 AS n UNION ALL SELECT n+1 FROM seq WHERE n < 10
) SELECT * FROM seq;
注意:
RETURNING是 MariaDB 相对 MySQL 的实用优势(尤其做批量删除时能拿到被删的行)。但INSERT ... RETURNING与自增 ID 的交互在部分驱动上有兼容问题,上线前用实际驱动验证。
7.4 在线 DDL
-- INSTANT:加列等操作秒级完成
ALTER TABLE orders ADD COLUMN note VARCHAR(100), ALGORITHM=INSTANT;
-- INPLACE:加索引、部分改列
ALTER TABLE orders ADD INDEX idx_note (note), ALGORITHM=INPLACE, LOCK=NONE;
-- 不支持时回退到 COPY,大表要用工具
ALTER TABLE orders MODIFY COLUMN amount DECIMAL(14,2), ALGORITHM=INPLACE;
与 MySQL 的差异:MariaDB 的 INSTANT 算法覆盖面与 MySQL 8 不同(尤其 10.x 版本对"加列到表末尾"才支持 INSTANT,中间位置不行)。执行前先
ALTER ... ALGORITHM=INSTANT试跑,报错再降级。
8. 备份与恢复
8.1 方式对比
| 方式 | 类型 | 锁 | 适用 |
|---|---|---|---|
mariadb-dump |
逻辑 | --single-transaction 下几乎无锁 |
中小库、跨版本迁移 |
mariadb-backup |
物理热备 | 无(InnoDB) | 大库生产标准 |
| 文件系统快照 | 物理 | 需冻结点 | 云盘、LVM |
mariadb-hotcopy |
物理冷备 | 全锁 | 老 MyISAM 场景 |
8.2 mariadb-dump
# 全库
mariadb-dump -uroot -p --single-transaction --quick \
--routines --triggers --events \
--default-character-set=utf8mb4 \
--all-databases > /backup/all_$(date +%F).sql
# 单库
mariadb-dump -uroot -p --single-transaction --databases appdb > /backup/appdb.sql
# 单表 / 只要结构 / 只要数据
mariadb-dump -uroot -p appdb orders > /backup/orders.sql
mariadb-dump -uroot -p --no-data --databases appdb > /backup/schema.sql
mariadb-dump -uroot -p --no-create-info appdb > /backup/data.sql
# 压缩
mariadb-dump -uroot -p --single-transaction --all-databases | gzip > /backup/all.sql.gz
# 记录 binlog 位点(搭从库用)
mariadb-dump -uroot -p --single-transaction --master-data=2 --all-databases > /backup/all.sql
关键参数:
| 参数 | 作用 |
|---|---|
--single-transaction |
InnoDB 一致性快照,不锁表 |
--quick |
逐行取,避免大表占内存 |
--routines --triggers --events |
带存储过程/触发器/事件 |
--master-data=2 |
注释形式记录 binlog 位点 |
--ignore-table=appdb.logs |
排除表 |
--where="..." |
条件导出 |
与 MySQL 的差异:MariaDB 的
--master-data参数名保留至今(MySQL 8.0.26+ 改名为--source-data)。反向迁移脚本时注意这个参数名差异。
8.3 恢复
mariadb -uroot -p < /backup/all_2026-11-05.sql
gunzip < /backup/appdb.sql.gz | mariadb -uroot -p
# 恢复前临时提速(导入窗口内)
mariadb -uroot -p -e "SET GLOBAL innodb_flush_log_at_trx_commit=2; SET GLOBAL sync_binlog=0;"
mariadb -uroot -p appdb < /backup/appdb.sql
mariadb -uroot -p -e "SET GLOBAL innodb_flush_log_at_trx_commit=1; SET GLOBAL sync_binlog=1;"
8.4 mariadb-backup(物理热备)
# 全量备份
mariadb-backup --backup --user=backup --password='Backup#2026' \
--target-dir=/backup/mariadb/20261105 --parallel=4 --compress
# 准备(回放 redo)
mariadb-backup --prepare --target-dir=/backup/mariadb/20261105
# 恢复:停库 → 清空 datadir → 拷回 → 改权限 → 启库
systemctl stop mariadb
mv /data/mariadb/data /data/mariadb/data.bak
mariadb-backup --copy-back --target-dir=/backup/mariadb/20261105
chown -R mysql:mysql /data/mariadb/data
systemctl start mariadb
# 增量备份
mariadb-backup --backup --target-dir=/backup/mariadb/inc1 \
--incremental-basedir=/backup/mariadb/20261105
# 准备增量链(先 prepare 全备,再逐个 prepare 增量)
mariadb-backup --prepare --target-dir=/backup/mariadb/20261105
mariadb-backup --prepare --target-dir=/backup/mariadb/20261105 \
--incremental-dir=/backup/mariadb/inc1
注意:
mariadb-backup由 Percona XtraBackup 分支而来,但与 XtraBackup 不通用(不能拿 XtraBackup 的备份给 mariadb-backup 恢复,反之亦然)。版本也要与 MariaDB 大版本匹配。
8.5 备份策略
| 库类型 | 全备 | 增量 | 保留 |
|---|---|---|---|
| 核心业务 | 每日 | 每 4 小时(binlog 持续) | 30 天 |
| 一般业务 | 每日 | 每 6 小时 | 14 天 |
| 报表库 | 每周 | 每日 | 30 天 |
9. binlog 与闪回
9.1 binlog 基础
SHOW VARIABLES LIKE 'log_bin';
SHOW VARIABLES LIKE 'binlog_format';
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';
SHOW BINARY LOGS;
SHOW MASTER STATUS\G
SHOW BINLOG EVENTS IN 'mariadb-bin.000012' LIMIT 20;
FLUSH BINARY LOGS;
PURGE BINARY LOGS TO 'mariadb-bin.000010';
PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 7 DAY);
与 MySQL 的差异:MariaDB 的复制命令仍使用
SHOW MASTER STATUS/SHOW SLAVE STATUS/CHANGE MASTER TO这套术语,没有跟随 MySQL 8.0.22+ 的SOURCE/REPLICA改名。从 MySQL 8 的脚本照搬新语法,在 MariaDB 上会报语法错误。
9.2 闪回(MariaDB 独有)
MariaDB 的 mariadb-binlog 支持 --flashback,可以生成"反向 SQL",用于回滚误删/误改。这是它相对 MySQL 最实用的运维差异之一。
# 1) 找到误操作的时间点或位置
mariadb-binlog --base64-output=DECODE-ROWS -v /data/mariadb/binlog/mariadb-bin.000012 | \
grep -n -i -E 'delete from|update' | head
# 2) 生成反向 SQL(注意:--flashback 要求 binlog_format=ROW)
mariadb-binlog --flashback \
--start-datetime="2026-11-05 10:00:00" \
--stop-datetime="2026-11-05 10:16:00" \
/data/mariadb/binlog/mariadb-bin.000012 > /backup/flashback.sql
# 3) 人工检查后执行
less /backup/flashback.sql
mariadb -uroot -p appdb < /backup/flashback.sql
限制:
--flashback只对binlog_format=ROW有效,且不能回滚 DDL(DROP TABLE/TRUNCATE无法闪回,只能靠备份)。生成的 SQL 必须人工过一遍再执行,直接管道进库等于把二次事故一起灌进去。
9.3 生产建议
log_bin=/data/mariadb/binlog/mariadb-bin
binlog_format=ROW
binlog_row_image=FULL
sync_binlog=1
binlog_expire_logs_seconds=604800
-- 确认 ROW 格式(闪回与复制的可靠性前提)
SHOW VARIABLES LIKE 'binlog_format';
10. 主从复制
10.1 主库配置
# 主库
server-id=1
log_bin=/data/mariadb/binlog/mariadb-bin
binlog_format=ROW
sync_binlog=1
innodb_flush_log_at_trx_commit=1
CREATE USER 'repl'@'10.0.0.%' IDENTIFIED BY 'Repl#2026';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.0.0.%';
FLUSH PRIVILEGES;
10.2 搭从库(传统位点方式)
# 1) 主库备份
mariadb-dump -uroot -p --single-transaction --master-data=2 --all-databases > /backup/full.sql
# 2) 从库导入
mariadb -uroot -p < /backup/full.sql
# 3) 从备份文件里取位点
head -30 /backup/full.sql | grep 'CHANGE MASTER'
CHANGE MASTER TO
MASTER_HOST='10.0.0.11',
MASTER_PORT=3306,
MASTER_USER='repl',
MASTER_PASSWORD='Repl#2026',
MASTER_LOG_FILE='mariadb-bin.000012',
MASTER_LOG_POS=1234567;
START SLAVE;
SHOW SLAVE STATUS\G
10.3 GTID 复制(MariaDB 机制不同)
# 主从都要
gtid_domain_id=1 # 每个主库唯一
server_id=1
log_slave_updates=ON
-- 主库
SET GLOBAL gtid_domain_id=1;
-- 从库
CHANGE MASTER TO
MASTER_HOST='10.0.0.11',
MASTER_USER='repl',
MASTER_PASSWORD='Repl#2026',
MASTER_USE_GTID=slave_pos;
START SLAVE;
与 MySQL 的差异:MariaDB 的 GTID 是
domain_id-server_id-sequence三段式,与 MySQL 的uuid:transaction_id完全不兼容。因此:
- MariaDB 主 + MySQL 从:不可行(GTID 无法互认)
- MySQL 主 + MariaDB 从:只能用传统位点方式,且要警惕 JSON 类型、字符集等差异 跨产品复制在业界被视为高风险操作,生产不建议。
10.4 状态判读
SHOW SLAVE STATUS\G
| 字段 | 期望 | 异常含义 |
|---|---|---|
Slave_IO_Running |
Yes |
Connecting = 网络/账号/防火墙 |
Slave_SQL_Running |
Yes |
No = 回放报错,看 Last_SQL_Error |
Seconds_Behind_Master |
0~5 | 持续增长 = 大事务、无主键、从库不足 |
Last_IO_Error / Last_SQL_Error |
空 | 先读原文再动手 |
Retrieved_Gtid_Set / Executed_Gtid_Set |
差值小 | 差集大 = 回放积压 |
-- 常用运维
STOP SLAVE;
START SLAVE;
STOP SLAVE SQL_THREAD;
START SLAVE SQL_THREAD;
-- 跳过一条错误(先搞清楚这条事务做了什么)
STOP SLAVE;
SET GLOBAL sql_slave_skip_counter=1;
START SLAVE;
-- 换主库前重置
STOP SLAVE;
RESET SLAVE ALL;
-- 只读从库
SET GLOBAL read_only=ON;
10.5 并行复制
SHOW VARIABLES LIKE 'slave_parallel_threads';
SHOW VARIABLES LIKE 'slave_parallel_mode';
slave_parallel_threads=4
slave_parallel_mode=optimistic # none / conservative / optimistic / aggressive
与 MySQL 的差异:MariaDB 用
slave_parallel_threads+slave_parallel_mode,MySQL 8 用replica_parallel_workers+replica_parallel_type。两边参数名和可选值都不一样,调优文档不能互相套用。
11. Galera 集群
11.1 特点
Galera 是 MariaDB 的同步多主集群方案(基于 wsrep),与 MySQL 的 Group Replication 定位相同但实现不同。
| 维度 | Galera | MySQL Group Replication |
|---|---|---|
| 一致性 | 认证式同步复制 | 多数派确认 |
| 写入 | 多主(可配置) | 单主为主 |
| 冲突处理 | 先到先得,后提交者回滚(死锁错误) | 类似 |
| 节点数 | 建议 3 或奇数 | 3 或奇数 |
| DDL | 需 wsrep_OSU_method 控制 |
需协调 |
11.2 配置(三节点)
# 每个节点,wsrep_node_name / wsrep_node_address 不同
[mysqld]
wsrep_on=ON
wsrep_provider=/usr/lib64/galera-4/libgalera_smm.so
wsrep_cluster_name="galera_prod"
wsrep_cluster_address="gcomm://10.0.0.11,10.0.0.12,10.0.0.13"
wsrep_node_name="node1"
wsrep_node_address="10.0.0.11"
wsrep_sst_method=rsync # 或 mariabackup(推荐)
wsrep_sst_auth="sst:Sst#2026"
binlog_format=ROW
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
innodb_flush_log_at_trx_commit=0 # Galera 常见取舍,按业务定
# 首个节点引导集群(只执行一次)
galera_new_cluster
# 其余节点正常启动,会自动加入
systemctl start mariadb
关键顺序:
galera_new_cluster只在第一个节点、且只执行一次。两个节点同时 bootstrap 会分裂成两个独立集群,恢复非常麻烦。
11.3 状态查看
SHOW STATUS LIKE 'wsrep_%';
SHOW STATUS LIKE 'wsrep_cluster_size'; -- 期望 3
SHOW STATUS LIKE 'wsrep_cluster_status'; -- 期望 Primary
SHOW STATUS LIKE 'wsrep_ready'; -- 期望 ON
SHOW STATUS LIKE 'wsrep_local_state_comment'; -- 期望 Synced
SHOW STATUS LIKE 'wsrep_connected'; -- 期望 ON
SHOW STATUS LIKE 'wsrep_flow_control_paused'; -- 越接近 0 越好
SHOW STATUS LIKE 'wsrep_local_recv_queue_avg';
| 指标 | 健康值 | 异常含义 |
|---|---|---|
wsrep_cluster_size |
等于预期节点数 | 少了说明节点掉线 |
wsrep_cluster_status |
Primary |
non-Primary 说明失去 quorum |
wsrep_ready |
ON |
OFF 表示不接收写入 |
wsrep_local_state_comment |
Synced |
Donor/Desynced/Joining 表示在同步 |
wsrep_flow_control_paused |
< 0.01 | 大说明写入被限流(从节点跟不上) |
wsrep_local_recv_queue_avg |
接近 0 | 大表示应用队列积压 |
11.4 运维操作
# 滚动重启(逐节点,保持 quorum)
# 1) 停一个节点
systemctl stop mariadb
# 2) 维护
# 3) 启动(不要用 galera_new_cluster)
systemctl start mariadb
# 4) 等 wsrep_local_state_comment=Synced 再操作下一个
-- 触发 SST(全量同步)
SET GLOBAL wsrep_sst_donor='node2';
-- 临时暂停节点写入
SET GLOBAL wsrep_on=OFF; -- 危险,会让该节点脱离集群
SET GLOBAL wsrep_on=ON; -- 重新加入会触发 SST
-- 查看集群成员
SHOW STATUS LIKE 'wsrep_incoming_addresses';
危险:
SET GLOBAL wsrep_on=OFF会让节点脱离集群但仍接受写入,重新加入时必须 SST(全量重传),数据量大的话耗时很长。非必要不要用。
11.5 常见故障
| 现象 | 原因 | 处理 |
|---|---|---|
wsrep_cluster_status = non-Primary |
失去 quorum(多数节点失联) | 恢复网络,或在确认安全后用 pc.bootstrap |
wsrep_ready = OFF |
节点未同步完成 | 等待,或查 SST 日志 |
写入报 Deadlock found |
多主冲突 | 业务重试,或改单主模式 |
wsrep_flow_control_paused 高 |
从节点应用跟不上 | 扩容、优化大事务 |
| SST 失败 | 端口/认证/磁盘不足 | 查 wsrep_sst_method 与日志 |
# 强制引导(最后手段,可能脑裂)
mysqld_safe --wsrep-new-cluster
危险:quorum 丢失后强制 bootstrap 会造成脑裂:两个集群各自接受写入,数据永久分叉。执行前必须确认其他节点确实全部下线。
12. 日志体系
12.1 日志位置
| 日志 | 默认位置 | 开启 |
|---|---|---|
| 错误日志 | /var/log/mariadb/mariadb.log(包)或 datadir/*.err |
log_error |
| 慢查询 | datadir/*-slow.log |
slow_query_log=ON |
| 通用日志 | datadir/*.log |
general_log=ON(生产禁开) |
| binlog | datadir/ 或 log_bin 指定 |
必须显式开 |
SHOW VARIABLES LIKE 'log_error';
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'general_log%';
SHOW VARIABLES LIKE 'log_bin';
12.2 错误日志
tail -f /var/log/mariadb/mariadb.log
grep -i -E 'error|warning|aborted' /var/log/mariadb/mariadb.log | tail -50
journalctl -u mariadb -p err --no-pager
| 关键字 | 含义 |
|---|---|
InnoDB: Unable to lock ./ibdata1 |
已有实例在跑,或 pid 残留 |
Do you already have another mysqld server running on port |
端口冲突 |
WSREP: failed to report last committed |
Galera 同步异常 |
Table './db/t' is marked as crashed |
表损坏 |
Too many connections |
连接数满 |
Aborted connection ... |
客户端异常断开 |
12.3 慢查询
SET GLOBAL slow_query_log=ON;
SET GLOBAL long_query_time=1;
SET GLOBAL log_slow_admin_statements=ON; -- 记录 DDL
SET GLOBAL log_slow_disabled_statements='sp'; -- 排除存储过程
mysqldumpslow -s t -t 20 /data/mariadb/logs/slow.log
pt-query-digest /data/mariadb/logs/slow.log > /tmp/report.txt
与 MySQL 的差异:MariaDB 多了
log_slow_disabled_statements、log_slow_admin_statements、log_slow_slave_statements等细粒度开关,且支持min_examined_row_limit更细的过滤。慢日志分析工具(pt-query-digest、mysqldumpslow)通用。
12.4 日志轮转
cat > /etc/logrotate.d/mariadb <<'EOF'
/data/mariadb/logs/*.log {
daily
rotate 14
missingok
compress
delaycompress
notifempty
copytruncate
}
EOF
logrotate -d /etc/logrotate.d/mariadb
13. 性能诊断
13.1 一眼看现状
SHOW GLOBAL STATUS LIKE 'Uptime';
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Threads_running';
SHOW GLOBAL STATUS LIKE 'Questions';
SHOW GLOBAL STATUS LIKE 'Slow_queries';
SHOW GLOBAL STATUS LIKE 'Max_used_connections';
SHOW ENGINE INNODB STATUS\G
-- QPS
SELECT ROUND(Questions/Uptime, 2) AS qps FROM (
SELECT VARIABLE_VALUE+0 AS Questions FROM information_schema.global_status WHERE VARIABLE_NAME='Questions') a,
(SELECT VARIABLE_VALUE+0 AS Uptime FROM information_schema.global_status WHERE VARIABLE_NAME='Uptime') b;
与 MySQL 的差异:MariaDB 10.5+ 仍保留
information_schema.global_status,但推荐用SHOW GLOBAL STATUS或performance_schema.global_status。老版本(10.1 及以前)才有information_schema.global_status的限制,新版一致。
13.2 会话与 SQL
SHOW FULL PROCESSLIST;
SELECT id, user, host, db, command, time, state, LEFT(info,120) AS sql
FROM information_schema.processlist
WHERE command <> 'Sleep' ORDER BY time DESC;
-- 杀会话 / 杀语句
KILL 12345;
KILL QUERY 12345;
-- MariaDB 独有:直接看某个线程的执行计划(10.1+)
SHOW EXPLAIN FOR 12345;
实用差异:
SHOW EXPLAIN FOR <thread_id>是 MariaDB 的杀手级排障命令——不用让业务重跑 SQL,直接看正在执行的语句的真实执行计划。MySQL 没有等价命令(要用EXPLAIN FOR CONNECTION,MySQL 8.0.19+ 才有)。
13.3 执行计划
EXPLAIN SELECT * FROM orders WHERE user_id=100;
EXPLAIN FORMAT=JSON SELECT * FROM orders WHERE user_id=100;
ANALYZE SELECT * FROM orders WHERE user_id=100; -- 真实执行并统计
ANALYZE FORMAT=JSON SELECT * FROM orders WHERE user_id=100;
SHOW WARNINGS;
ANALYZE FORMAT=JSON 是 MariaDB 相对 MySQL EXPLAIN ANALYZE 的对应能力,输出字段不同但用途相同。
13.4 锁与阻塞
-- 当前事务
SELECT * FROM information_schema.innodb_trx\G
-- 锁等待(MariaDB 10.x 用 information_schema 的 innodb_lock_waits)
SELECT * FROM information_schema.innodb_lock_waits\G
SELECT * FROM information_schema.innodb_locks\G
-- 元数据锁
SELECT * FROM information_schema.metadata_lock_info;
-- 显示谁在等谁
SHOW PROCESSLIST;
与 MySQL 的差异:MySQL 8 已移除
information_schema.innodb_locks/innodb_lock_waits,改用performance_schema.data_locks/data_lock_waits。MariaDB 仍保留 information_schema 的这套视图,所以从 MySQL 8 迁过来的监控脚本会报"表不存在",反之亦然。
13.5 InnoDB 指标
-- buffer pool 命中率
SELECT ROUND(100 - (SELECT VARIABLE_VALUE FROM information_schema.global_status
WHERE VARIABLE_NAME='Innodb_buffer_pool_reads') * 100 /
(SELECT VARIABLE_VALUE FROM information_schema.global_status
WHERE VARIABLE_NAME='Innodb_buffer_pool_read_requests'), 4) AS hit_pct;
-- 脏页比例
SELECT
(SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_dirty') /
(SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME='Innodb_buffer_pool_pages_total') * 100 AS dirty_pct;
SHOW GLOBAL STATUS LIKE 'Innodb_row_lock_waits';
SHOW GLOBAL STATUS LIKE 'Innodb_deadlocks';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_wait_free';
13.6 服务器层
top -H -p $(pgrep -x mariadbd)
iostat -x 1 5
vmstat 1 5
free -h
dmesg | grep -i -E 'oom|killed process'
14. 空间与容量
14.1 库表大小
SELECT table_schema, table_name,
ROUND((data_length+index_length)/1024/1024, 2) AS total_mb,
ROUND(data_length/1024/1024, 2) AS data_mb,
ROUND(index_length/1024/1024, 2) AS index_mb,
table_rows, engine
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys')
ORDER BY (data_length+index_length) DESC LIMIT 20;
-- 按库汇总
SELECT table_schema, ROUND(SUM(data_length+index_length)/1024/1024/1024, 2) AS gb
FROM information_schema.tables GROUP BY table_schema ORDER BY gb DESC;
14.2 磁盘盘点
df -h
du -sh /data/mariadb/*
du -sh /data/mariadb/binlog/*
ls -lh /data/mariadb/data/ | sort -k5 -h | tail -20
常见原因:binlog 堆积、慢日志/通用日志、ibdata 膨胀、长事务导致 undo 不回收、ibtmp1。
14.3 空间回收
-- 表碎片检查
SELECT table_schema, table_name, engine,
ROUND(data_free/1024/1024,1) AS free_mb,
ROUND(data_free/(data_length+index_length+1)*100,1) AS frag_pct
FROM information_schema.tables
WHERE data_free > 100*1024*1024
ORDER BY data_free DESC;
-- 回收(重建表)
ALTER TABLE big_logs ENGINE=InnoDB;
OPTIMIZE TABLE big_logs; -- InnoDB 等价于重建
-- InnoDB 表空间文件
SELECT file_id, file_name, ROUND(total_extents*extent_size/1024/1024,1) AS mb
FROM information_schema.innodb_sys_tablespaces;
注意:
OPTIMIZE TABLE需要等量临时空间,磁盘不足时会失败并可能留下中间文件。磁盘紧张时先清 binlog,再考虑 OPTIMIZE。
15. 升级与迁移
15.1 升级路径
10.6 → 10.11 → 11.4 → 11.8 → 12.3 → 13.x
规则:
- 不能跨大版本直跳(10.6 不能直接升 12.3,需逐级)。
- 升级前必须备份,且
mariadb-upgrade会升级系统表,不可逆。 - 小版本内可以直接升(12.3.2 → 12.3.3)。
- 12.3 的
innodb_snapshot_isolation=ON默认值变化会影响REPEATABLE READ下的冲突行为,升级前必须用业务 SQL 做隔离级别回归。
15.2 就地升级
# 1) 备份
mariadb-backup --backup --target-dir=/backup/pre_upgrade --user=backup -p
mariadb-dump -uroot -p --single-transaction --all-databases > /backup/pre_upgrade.sql
# 2) 记录基线
mariadb -uroot -p -e "SELECT VERSION(); SHOW VARIABLES;" > /backup/vars_before.txt
# 3) 停库
systemctl stop mariadb
# 4) 升级包
dnf update -y MariaDB-server MariaDB-client
# 5) 启动
systemctl start mariadb
# 6) 升级系统表(MariaDB 仍需这一步,与 MySQL 8.0.16+ 不同)
mariadb-upgrade -uroot -p
# 7) 验证
mariadb -uroot -p -e "SELECT VERSION(); CHECK TABLE mysql.user;"
tail -100 /var/log/mariadb/mariadb.log | grep -i -E 'error|upgrade'
与 MySQL 的差异:MySQL 8.0.16+ 已废弃
mysql_upgrade(服务端自动升级),但 MariaDB 至今仍需要手工执行mariadb-upgrade。这一步不能省,否则系统表结构不匹配会导致权限、时区等功能异常。
15.3 升级后检查
SELECT VERSION();
SELECT * FROM mysql.user LIMIT 3; -- 系统表可读
CHECK TABLE mysql.user, mysql.db, mysql.global_priv;
SHOW WARNINGS;
-- 确认字符集没被改回 latin1
SHOW VARIABLES LIKE 'character_set_server';
-- 确认引擎
SELECT DISTINCT engine FROM information_schema.tables WHERE table_schema='appdb';
15.4 从 MySQL 迁移到 MariaDB
这是实际工作中最常见的迁移方向,注意以下不兼容点:
| 项目 | MySQL 8 特性 | MariaDB 处理 |
|---|---|---|
| 认证插件 | caching_sha2_password |
不支持,必须重建用户为 mysql_native_password |
| 字符集排序 | utf8mb4_0900_ai_ci |
不支持,改 utf8mb4_general_ci 或 utf8mb4_unicode_ci |
| JSON | 原生二进制 JSON | LONGTEXT + 校验,函数基本兼容但存储不同 |
| 复制术语 | SOURCE / REPLICA |
仍用 MASTER / SLAVE |
| 参数 | innodb_redo_log_capacity |
不支持,用 innodb_log_file_size |
| 窗口函数 | 支持 | 10.2+ 支持,基本兼容 |
| CTE | 支持 | 10.2+ 支持 |
CHECK 约束 |
8.0.16+ 强制执行 | 10.2+ 强制执行 |
# 迁移流程
# 1) MySQL 端导出(注意排除不兼容项)
mysqldump -uroot -p --single-transaction --routines --triggers --events \
--set-gtid-purged=OFF --default-character-set=utf8mb4 \
--all-databases > /backup/from_mysql.sql
# 2) 清理不兼容语法
sed -i 's/utf8mb4_0900_ai_ci/utf8mb4_general_ci/g' /backup/from_mysql.sql
sed -i '/caching_sha2_password/d' /backup/from_mysql.sql
# 3) 导入 MariaDB
mariadb -uroot -p < /backup/from_mysql.sql
# 4) 重建用户
mariadb -uroot -p -e "CREATE USER 'app'@'%' IDENTIFIED BY 'App#2026'; GRANT ALL ON appdb.* TO 'app'@'%';"
# 5) 校验
mariadb -uroot -p -e "SELECT table_schema, COUNT(*) FROM information_schema.tables GROUP BY 1;"
15.5 从 MariaDB 迁移到 MySQL
反向迁移的坑:
- MariaDB 的
mysql.global_priv表结构与 MySQL 完全不同,不能直接拷贝mysql库。 RETURNING语法、SEQUENCE、系统版本化表、动态列在 MySQL 中不存在。- Aria 引擎的表要转 InnoDB。
- binlog 格式与 GTID 不兼容,只能逻辑迁移。
# 推荐:逻辑导出 + 目标端重建
mariadb-dump -uroot -p --single-transaction --routines --triggers --events \
--default-character-set=utf8mb4 --databases appdb > /backup/to_mysql.sql
# 目标 MySQL 端
mysql -uroot -p < /backup/to_mysql.sql
16. 高频故障速查
16.1 连不上
| 现象 | 排查 |
|---|---|
Can't connect to local server through socket |
socket 路径不对 / 服务未起 |
Access denied for user 'root'@'localhost' |
root 用 unix_socket,当前系统用户不是 root |
Host 'x' is not allowed to connect |
用户 host 不匹配 |
Too many connections |
连接数满 |
Host 'x' is blocked |
max_connect_errors 触发,FLUSH HOSTS |
-- root 被 unix_socket 锁住时(用系统 root)
sudo mariadb -uroot
-- 改成密码认证
ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('New#2026');
FLUSH PRIVILEGES;
最常见坑:用普通系统用户执行
mariadb -uroot报 Access denied,是因为 root 走unix_socket。要么sudo -i切到 root,要么把 root 改成密码认证。这不是配置错误。
16.2 忘记 root 密码
systemctl stop mariadb
mariadbd --skip-grant-tables --skip-networking --user=mysql &
mariadb -uroot
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('New#2026');
FLUSH PRIVILEGES;
mariadb-admin -uroot -p shutdown
systemctl start mariadb
16.3 表损坏
CHECK TABLE appdb.orders;
REPAIR TABLE appdb.orders; -- MyISAM/Aria
REPAIR TABLE appdb.orders EXTENDED;
InnoDB 损坏:
[mysqld]
innodb_force_recovery=1
逐级放开到 6(最危险),能启动就立刻导出:
mariadb-dump -uroot -p --single-transaction --all-databases > /backup/emergency.sql
危险:
innodb_force_recovery >= 4时表只读且可能丢数据,6会跳过 redo 回放。只在"不要数据也要把库拉起来"时用,用完改回 0。
16.4 主从中断
SHOW SLAVE STATUS\G
Last_SQL_Error |
处理 |
|---|---|
Duplicate entry |
主从不一致,先比对再决定跳过 |
Unknown database |
从库缺库,补建 |
Error_code: 1062 |
唯一键冲突 |
Got fatal error 1236 |
binlog 被清理,需重做全量 |
Could not find first log file |
位点错误或 binlog 丢失 |
16.5 Galera 异常
SHOW STATUS LIKE 'wsrep_cluster_status';
SHOW STATUS LIKE 'wsrep_ready';
SHOW STATUS LIKE 'wsrep_local_state_comment';
| 状态 | 处理 |
|---|---|
non-Primary |
恢复网络;确认安全后 pc.bootstrap |
wsrep_ready=OFF |
等同步完成,查 SST 日志 |
Donor/Desynced |
正在全量传输,等待并检查带宽 |
| 频繁 flow control | 从节点跟不上,扩容或拆大事务 |
16.6 磁盘满
df -h
du -sh /data/mariadb/* | sort -h
SHOW BINARY LOGS;
PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY);
急救顺序:清 binlog → 清慢日志 → 扩盘。不要在磁盘满时做 OPTIMIZE。
16.7 时区与字符集
SELECT @@system_time_zone, @@global.time_zone, NOW();
SHOW VARIABLES LIKE 'character_set%';
default-time-zone='+08:00'
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
# 时区表
mariadb-tzinfo-to-sql /usr/share/zoneinfo | mariadb -uroot -p mysql
17. 危险命令与避坑清单
| 命令 | 后果 | 防护 |
|---|---|---|
DROP DATABASE |
整库消失 | 收回 DDL 权限 + 备份 |
DROP TABLE / TRUNCATE |
数据清空,无法闪回 | 先备份;TRUNCATE 不进 binlog 的 ROW 回滚 |
DELETE FROM t; |
全表删、undo 暴涨 | sql_safe_updates=1 |
UPDATE t SET c=1; |
全表改 | 同上 |
PURGE BINARY LOGS 误删 |
从库断链 | 先确认从库位点 |
galera_new_cluster 重复执行 |
脑裂,数据分叉 | 只在首节点执行一次 |
SET GLOBAL wsrep_on=OFF |
节点脱群但仍写入 | 非必要不用 |
innodb_force_recovery=6 |
跳过 redo,数据可能丢 | 先备份,用完归 0 |
kill -9 mariadbd |
崩溃恢复 | 用 mariadb-admin shutdown |
mariadb-binlog --flashback 直接执行 |
可能二次破坏 | 生成 SQL 后人工检查 |
只 mysqldump 不 mariadb-upgrade |
升级后权限/时区异常 | 升级必跑 mariadb-upgrade |
从 MySQL 8 直接拷 mysql 库 |
权限表结构不兼容 | 逻辑导出 + 重建用户 |
rm binlog 文件 |
索引文件不一致,启动失败 | 用 PURGE BINARY LOGS |
17.1 变更前检查清单
# 1) 确认实例与角色
mariadb -uroot -p -e "SELECT @@hostname, @@port, @@datadir; SHOW SLAVE STATUS\G" | head -20
# 2) 备份
mariadb-dump -uroot -p --single-transaction --databases <db> > /backup/pre_change.sql
# 3) 看表大小
mariadb -uroot -p -e "SELECT table_name, table_rows, ROUND((data_length+index_length)/1024/1024) mb FROM information_schema.tables WHERE table_schema='<db>' ORDER BY 3 DESC LIMIT 10;"
# 4) 看长事务与锁
mariadb -uroot -p -e "SELECT * FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 5;"
# 5) 看复制延迟
mariadb -uroot -p -e "SHOW SLAVE STATUS\G" | grep Seconds_Behind
# 6) Galera 状态
mariadb -uroot -p -e "SHOW STATUS LIKE 'wsrep_cluster_size'; SHOW STATUS LIKE 'wsrep_local_state_comment';"
18. 附录:巡检脚本与速查
18.1 巡检脚本
#!/usr/bin/env bash
# 用法:./mariadb_health.sh (依赖 ~/.my.cnf)
set -euo pipefail
mariadb -N -B -e "
SELECT '版本', VERSION()
UNION ALL SELECT '运行时长(小时)', ROUND(VARIABLE_VALUE/3600,1) FROM information_schema.global_status WHERE VARIABLE_NAME='Uptime'
UNION ALL SELECT 'QPS', ROUND((SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME='Questions')/
(SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME='Uptime'),1)
UNION ALL SELECT '当前连接', VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME='Threads_connected'
UNION ALL SELECT '活跃线程', VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME='Threads_running'
UNION ALL SELECT '最大连接数', VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME='Max_used_connections'
UNION ALL SELECT '慢查询数', VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME='Slow_queries'
UNION ALL SELECT '死锁次数', VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME='Innodb_deadlocks';
"
echo "--- 库大小 TOP5 ---"
mariadb -e "SELECT table_schema, ROUND(SUM(data_length+index_length)/1024/1024/1024,2) gb
FROM information_schema.tables GROUP BY table_schema ORDER BY gb DESC LIMIT 5;"
echo "--- 非 Sleep 会话 ---"
mariadb -e "SELECT id,user,host,db,command,time,LEFT(info,70) sql
FROM information_schema.processlist WHERE command<>'Sleep' ORDER BY time DESC LIMIT 10;"
echo "--- 长事务 ---"
mariadb -e "SELECT trx_id,TIMESTAMPDIFF(MINUTE,trx_started,NOW()) min,trx_rows_locked
FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 5;"
echo "--- 复制状态 ---"
mariadb -e "SHOW SLAVE STATUS\G" | grep -E 'Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master' || true
echo "--- Galera ---"
mariadb -e "SHOW STATUS LIKE 'wsrep_cluster_size'; SHOW STATUS LIKE 'wsrep_local_state_comment';" || true
18.2 单行命令速查
mariadb-admin -uroot -p status
mariadb-admin -uroot -p ping
mariadb-admin -uroot -p processlist
mariadb-admin -uroot -p extended-status | grep Threads
mariadb-admin -uroot -p variables | grep buffer_pool
mariadb-admin -uroot -p flush-logs
mariadb-admin -uroot -p flush-hosts
mariadb-admin -uroot -p shutdown
mariadb-check -uroot -p --all-databases
mariadb-dump -uroot -p --single-transaction --all-databases > all.sql
mariadb-backup --backup --target-dir=/backup/x --user=backup -p
mariadb-binlog --flashback mariadb-bin.000012 > flashback.sql
18.3 关键参数对照(MariaDB vs MySQL)
| 用途 | MariaDB | MySQL 8 |
|---|---|---|
| redo 大小 | innodb_log_file_size |
innodb_redo_log_capacity |
| 并行复制线程 | slave_parallel_threads |
replica_parallel_workers |
| 并行复制模式 | slave_parallel_mode |
replica_parallel_type |
| 复制术语 | MASTER / SLAVE |
SOURCE / REPLICA |
| 语句超时 | max_statement_time |
max_execution_time |
| binlog 过期 | binlog_expire_logs_seconds / expire_logs_days |
binlog_expire_logs_seconds |
| 默认排序规则 | utf8mb4_general_ci |
utf8mb4_0900_ai_ci |
| 认证插件 | mysql_native_password |
caching_sha2_password |
18.4 关键路径与端口
| 项 | 值 |
|---|---|
| 默认端口 | 3306 |
| Galera 复制端口 | 4567(组通信)、4444(SST)、4568(IST) |
| 配置文件 | /etc/my.cnf、/etc/my.cnf.d/(RHEL)/ /etc/mysql/mariadb.conf.d/(Debian) |
| 数据目录 | /var/lib/mysql(包)/ /data/mariadb/data(自定义) |
| 错误日志 | /var/log/mariadb/mariadb.log |
| 备份工具 | mariadb-backup、mariadb-dump |
| 服务名 | mariadb |
附:与工作区其他手册的配合
- 操作系统层见
CentOS-7-10-常规运维指令手册.md/Ubuntu-常用运维指令手册.md - 放行端口:
firewall-cmd --add-service=mysql --permanent(Galera 另需 4567/4444/4568) - SELinux 下改 datadir:
semanage fcontext -a -t mysqld_db_t "/data/mariadb(/.*)?"+restorecon -Rv /data/mariadb - 与
MySQL-常用运维指令手册.md配合使用:通用 SQL 与 InnoDB 调优思路一致,但工具名、认证插件、复制术语、GTID 格式、锁视图这五处必须按本手册处理