Appearance
MySQL 安装与基础
MySQL 运维的第一步是把实例装起来、配置好、能正常启停和连接。后续的备份恢复、主从复制、性能排查,都建立在"这个实例能正常跑"的基础上。
一、版本和部署方式的选择
现在生产环境里最常见的是 MySQL 8.0,也有一些 5.7 的存量环境。如果没有历史包袱(老应用必须用 5.7 的某些特性),新环境通常直接选 8.0 LTS 或者发行版/云厂商提供的稳定版本。
几种部署方式各有适用场景:
| 方式 | 适合什么场景 | 要注意什么 |
|---|---|---|
| 系统包安装(yum/apt) | 测试环境、单机使用 | 版本受仓库限制,不一定是最新版 |
| 官方 Yum/Apt 仓库 | 自建标准化环境 | 版本相对可控,但要注意不同小版本的变化 |
| 二进制包 | 离线部署、固定版本号不能变 | 目录结构、systemd 都要自己处理 |
| 源码编译 | 需要特殊编译参数 | 维护成本高,一般情况下不优先选 |
| 容器部署 | 测试、开发、K8s 环境 | 数据目录和配置的持久化要处理好,否则容器重启数据就没了 |
生产 MySQL 的安装来源尽量统一。用系统包装了一半又手工覆盖一半,后面升级和排查会找不到到底用的是哪个版本的哪个包。
二、包安装
RHEL/Rocky/CentOS 通常先配 MySQL 官方仓库再安装:
bash
yum install -y https://repo.mysql.com/mysql80-community-release-el8.rpm
yum install -y mysql-community-serverUbuntu/Debian:
bash
apt update
apt install -y mysql-server确认版本:
bash
mysql --version
mysqld --version包安装后文件分布在系统各个位置,常见的:
| 路径 | 是什么 |
|---|---|
/etc/my.cnf | RHEL 系配置文件入口 |
/etc/mysql/my.cnf | Debian/Ubuntu 配置文件入口 |
/var/lib/mysql | 默认数据目录 |
/var/log/mysqld.log | RHEL 系错误日志 |
/var/log/mysql/error.log | Debian/Ubuntu 错误日志 |
/usr/sbin/mysqld | 服务端程序 |
/usr/bin/mysql | 客户端程序 |
不同发行版和安装源的路径可能有差异,查具体文件位置:
bash
rpm -ql mysql-community-server | head # RHEL 系
dpkg -L mysql-server | head # Debian 系三、二进制包部署
二进制包适合需要固定版本和离线部署的场景。解压、建用户、规划目录三步走:
bash
tar -xf mysql-8.0.x-linux-glibc2.28-x86_64.tar.xz -C /usr/local/
ln -s /usr/local/mysql-8.0.x-linux-glibc2.28-x86_64 /usr/local/mysql创建 MySQL 专用的系统用户和数据目录:
bash
groupadd mysql
useradd -r -g mysql -s /sbin/nologin mysql
mkdir -p /data/mysql/{data,logs,tmp}
chown -R mysql:mysql /data/mysqluseradd -r 创建系统账号(UID 一般在系统账号范围),-s /sbin/nologin 表示这个账号不能登录 shell——MySQL 进程用这个身份运行,不需要人登录。
数据目录里面放着 InnoDB 表空间文件、系统库表、undo 表空间等关键数据。目录权限要收紧,不能随便给人读。
几个和数据、日志相关的概念,后面备份复制都会用到:
| 对象 | 在哪 | 干什么用 |
|---|---|---|
| 数据目录(datadir) | datadir 参数指定 | 存放表空间、系统库(mysql/sys 等)、undo 表空间 |
| 错误日志 | log_error 参数指定 | 记录启动失败、崩溃恢复、复制异常、权限错误 |
| binlog | log_bin 参数指定 | Server 层逻辑变更日志,用于复制和时间点恢复 |
| redo log | InnoDB 内部日志 | 记录已提交事务需要重放的页变更,用于崩溃恢复 |
| undo log | InnoDB undo 表空间 | 支持事务回滚和 MVCC 读取历史版本 |
binlog 和 redo 的职责不同:binlog 记录的是"某条 SQL 提交了",是 Server 层的;redo 记录的是"某个数据页被改了",是 InnoDB 引擎层的。崩溃恢复靠 redo,复制和按时间点恢复靠 binlog。两者放在一起并不能互相替代。
初始化数据目录:
bash
/usr/local/mysql/bin/mysqld \
--initialize \
--user=mysql \
--basedir=/usr/local/mysql \
--datadir=/data/mysql/data--initialize 会创建系统表空间、系统库(mysql 库)、生成初始 root 密码,并把临时密码写到错误日志里。这个命令只在第一次使用时执行——重新 --initialize 会让已有数据全部丢失。
四、配置文件
一份最小但完整的配置,把几个核心要素都写清楚:
ini
[mysqld]
server_id=1
port=3306
user=mysql
basedir=/usr/local/mysql
datadir=/data/mysql/data
socket=/data/mysql/tmp/mysql.sock
pid-file=/data/mysql/tmp/mysqld.pid
log_error=/data/mysql/logs/error.log
character_set_server=utf8mb4
collation_server=utf8mb4_0900_ai_ci
max_connections=500
open_files_limit=65535
innodb_buffer_pool_size=1G
innodb_flush_log_at_trx_commit=1
sync_binlog=1
log_bin=/data/mysql/logs/mysql-bin
binlog_format=ROW
binlog_expire_logs_seconds=604800每个参数解决什么问题:
| 参数 | 干什么 | 为什么要注意 |
|---|---|---|
server_id | 复制拓扑里给每个实例唯一编号 | 重复会导致复制异常,就算单机也先写上 |
datadir | 数据目录位置 | 改到已有目录前要确认里面没有旧实例的数据 |
character_set_server=utf8mb4 | 默认字符集 | MySQL 里的 utf8 不是完整 UTF-8,新库都用 utf8mb4 |
innodb_buffer_pool_size | InnoDB 缓冲池大小 | 内存规划的核心参数,影响查询到底是读内存还是读磁盘 |
log_bin | 开启 binlog | 不开启就无法做时间点恢复,也无法搭主从 |
binlog_format=ROW | 行格式 binlog | 复制和回放更精确,少一些语句级歧义 |
innodb_flush_log_at_trx_commit=1 | 每次提交都刷 redo 到磁盘 | 防止宕机后"事务提交了但日志没落盘" |
sync_binlog=1 | 每次事务都同步 binlog 到磁盘 | 和上面那条配套,确保 redo 和 binlog 都落盘了再告诉客户端"提交成功" |
这两项是常放在一起讨论的。innodb_flush_log_at_trx_commit=1 关注的是 redo 刷盘,sync_binlog=1 关注的是 binlog 刷盘。核心业务库一般保持双 1,优先保证数据安全。写入量特别大的场景,再根据磁盘能力和可接受的数据丢失窗口来评估是否调低。
配置文件改完之后的确认:MySQL 没有完全等价于 nginx -t 的配置检查命令,通常靠重启实例来验证。所以生产上改配置前备份旧配置,改完之后在低峰窗口重启观察。
五、systemd 管理
包安装通常自带 systemd unit:
bash
systemctl enable mysqld
systemctl start mysqld
systemctl status mysqld --no-pager二进制部署需要手写 unit 文件,保存为 /etc/systemd/system/mysqld.service:
ini
[Unit]
Description=MySQL Server
After=network.target
[Service]
Type=forking
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf
ExecStop=/usr/local/mysql/bin/mysqladmin --defaults-file=/etc/my.cnf shutdown
LimitNOFILE=65535
Restart=on-failure
PrivateTmp=false
[Install]
WantedBy=multi-user.target保存后加载并启动:
bash
systemctl daemon-reload
systemctl enable mysqld
systemctl start mysqldLimitNOFILE 设置进程可以打开的句柄数上限。MySQL 的连接数、表数量、binlog 文件数量都消耗文件描述符——默认的 systemd 文件描述符限制(通常 1024 或 4096)不一定够。如果 open_files_limit 配置大了但 systemd 这边限制了,实际生效的会是两边的较小值。
六、首次登录和改密码
包安装后的临时 root 密码写在错误日志里:
bash
grep 'temporary password' /var/log/mysqld.log用临时密码登录,然后立刻改掉:
bash
mysql -uroot -psql
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewStrongPassword_123!';确认当前身份:
sql
SELECT USER(), CURRENT_USER();USER() 返回的是客户端声称的用户名和来源地址,CURRENT_USER() 返回的是 MySQL 最终匹配到的授权账号。排查权限问题时,后者更关键——你以为连的是 root@localhost,实际可能被匹配成了 root@%。
七、常用客户端和管理命令
连接方式:
bash
# TCP 连接
mysql -h 127.0.0.1 -P 3306 -uroot -p
# 本地 socket 连接(不经过 TCP)
mysql -uroot -p --socket=/data/mysql/tmp/mysql.sockMySQL 的配套工具:
| 工具 | 干什么用 |
|---|---|
mysql | 交互式客户端,执行 SQL |
mysqladmin | ping、shutdown、status 等管理操作 |
mysqldump | 逻辑备份,导出 SQL |
mysqlbinlog | 查看和回放 binlog 内容 |
mysqlshow | 快速看有哪些库、表 |
检测实例是否活着:
bash
mysqladmin -uroot -p ping查看关键变量和状态:
sql
SHOW VARIABLES LIKE 'datadir';
SHOW VARIABLES LIKE 'log_bin';
SHOW VARIABLES LIKE 'character_set_server';
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Uptime';八、目录和日志确认
先知道关键路径在哪:
sql
SHOW VARIABLES WHERE Variable_name IN (
'datadir',
'log_error',
'general_log_file',
'slow_query_log_file',
'socket'
);错误日志是排查的第一现场——启动失败、崩溃恢复、复制错误、权限错误都会写在这里:
bash
tail -n 100 /data/mysql/logs/error.log确认端口和进程:
bash
ss -lntp | grep ':3306'
ps -ef | grep '[m]ysqld'grep '[m]ysqld' 的技巧是方括号让正则匹配 m 而不是字面字符串 [m],这样 grep 自己的命令行不会出现在结果里。
九、装完之后的基础安全处理
新装 MySQL 至少处理这几项:
| 做什么 | 怎么处理 |
|---|---|
| 改 root 密码 | 从临时密码改成强密码 |
| 删匿名用户 | 匿名用户可以无密码连接 |
| 不开放远程 root | root 只保留 localhost 来源 |
| 删 test 库 | 默认创建的 test 库权限较宽,生产不需要 |
| 确认 binlog 开启 | 为后续备份恢复和复制做准备 |
| 确认错误日志路径和权限 | 保证日志能正常写入 |
对应的 SQL:
sql
SELECT user, host FROM mysql.user; -- 先看有哪些账号
DROP USER IF EXISTS ''@'localhost'; -- 删除匿名用户
DROP DATABASE IF EXISTS test; -- 删除 test 库
FLUSH PRIVILEGES;正式环境的 root 通常只保留本机 socket 登录。应用账号按库、按最小需要的权限来建,不和 root 混用。