MariaDB 常用运维指令手册

运维指令手册 43.4 KB 原文

MariaDB 常用运维指令手册

适用版本:MariaDB 10.11 / 11.4 LTS / 11.8 LTS / 12.3 LTS / 13.x(滚动) 约定:# root 或 sudo,$ 普通用户,MariaDB [(none)]> 客户端提示符,<xxx> 为占位符。 差异标注:正文用 > **与 MySQL 的差异** 引用块标注易踩坑之处。 更新时间:2026-11


目录

  1. 版本与支持周期
  2. 下载地址与安装
  3. 服务启停与初始化
  4. 客户端连接与工具链
  5. 配置文件与参数
  6. 账号、认证与权限
  7. 库表与引擎
  8. 备份与恢复
  9. binlog 与闪回
  10. 主从复制
  11. Galera 集群
  12. 日志体系
  13. 性能诊断
  14. 空间与容量
  15. 升级与迁移
  16. 高频故障速查
  17. 危险命令与避坑清单
  18. 附录:巡检脚本与速查

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

规则:

  1. 不能跨大版本直跳(10.6 不能直接升 12.3,需逐级)。
  2. 升级前必须备份,且 mariadb-upgrade 会升级系统表,不可逆。
  3. 小版本内可以直接升(12.3.2 → 12.3.3)。
  4. 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 格式、锁视图这五处必须按本手册处理
MariaDB 常用运维指令手册 - 知识库 - 起航社区