目录

MySQL-11 配置参数详解

1. 配置文件结构

1.1 配置文件位置

# MySQL 按以下顺序读取配置文件
/etc/my.cnf
/etc/mysql/my.cnf
/usr/local/mysql/etc/my.cnf
~/.my.cnf

# 查看 MySQL 读取了哪些配置文件
mysql --verbose --help | grep "Default options" -A 1

# Docker 中挂载配置
docker run ... -v /host/my.cnf:/etc/mysql/conf.d/custom.cnf mysql:8.0

1.2 配置文件结构

# my.cnf 结构
[mysqld]          # mysqld 服务器进程
key = value

[mysql]           # mysql 客户端
prompt = 'mysql[\d]> '

[client]          # 所有客户端程序
host = 127.0.0.1
port = 3306

1.3 动态修改配置

-- 查看当前值
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW GLOBAL VARIABLES LIKE 'max_connections';
SHOW SESSION VARIABLES LIKE 'sort_buffer_size';

-- 动态修改(部分参数支持,不需要重启)
SET GLOBAL max_connections = 500;
SET SESSION sort_buffer_size = 4 * 1024 * 1024;

-- MySQL 8.0 持久化动态修改(写入 mysqld-auto.cnf,重启生效)
SET PERSIST max_connections = 500;
SET PERSIST_ONLY innodb_buffer_pool_size = 4 * 1024 * 1024 * 1024;
-- PERSIST: 立即生效 + 持久化
-- PERSIST_ONLY: 只持久化,下次重启生效

-- 查看持久化配置
SELECT * FROM performance_schema.persisted_variables;

-- 删除持久化配置
RESET PERSIST max_connections;

2. 内存相关配置

2.1 InnoDB Buffer Pool(最重要!)

# ==========================================
# 建议设为物理内存的 60~80%
# 8GB 内存机器:设 5~6GB
# 16GB 内存机器:设 10~12GB
# ==========================================
innodb_buffer_pool_size = 8G

# 多实例(每个实例独立的 LRU 链表,减少锁竞争)
# 推荐:innodb_buffer_pool_size >= 1G 时使用多实例
# 每个实例至少 1GB
innodb_buffer_pool_instances = 8

# 预热(启动时从文件加载 Buffer Pool 内容,减少冷启动时间)
innodb_buffer_pool_load_at_startup  = ON
innodb_buffer_pool_dump_at_shutdown = ON
innodb_buffer_pool_dump_pct         = 25  # 导出 LRU 链表前 25%

2.2 连接级别内存(每个连接独占)

# 以下参数是每个连接都会分配的内存,要考虑 max_connections 的放大效应
# 总内存消耗 ≈ max_connections × (sort_buffer + join_buffer + read_buffer + read_rnd_buffer)

sort_buffer_size      = 2M    # 排序缓冲(默认 256KB,过大对慢查询反而有害)
join_buffer_size      = 2M    # JOIN 缓冲(BNL 使用,默认 256KB)
read_buffer_size      = 1M    # 顺序读缓冲(MyISAM 和部分 InnoDB 操作)
read_rnd_buffer_size  = 1M    # 随机读缓冲
tmp_table_size        = 32M   # 内存临时表大小(超出转磁盘)
max_heap_table_size   = 32M   # 内存 HEAP 表大小(与 tmp_table_size 取较小值)

# 注意:sort_buffer 等是按需分配,不是启动就占用

2.3 全局内存缓冲

# 键值缓存(MyISAM 索引缓存,InnoDB 用户可设小)
key_buffer_size       = 32M    # 默认 8M,MyISAM 用户调大,InnoDB 用户保持小

# 查询缓存(MySQL 8.0 已移除)
query_cache_type      = OFF    # 关闭
query_cache_size      = 0

# binlog 缓存
binlog_cache_size     = 1M     # 每个事务的 Binlog 写入缓存
max_binlog_cache_size = 2G     # 单个事务的最大 Binlog 缓存

# 线程缓存
thread_cache_size     = 100    # 空闲线程缓存数量(减少线程创建开销)

2.4 内存估算

# MySQL 内存使用估算公式
# 固定内存:
#   innodb_buffer_pool_size
#   innodb_log_buffer_size
#   key_buffer_size
#   query_cache_size(5.7)
#
# 动态内存(per connection):
#   thread_stack(512KB/连接)
#   sort_buffer_size(按需,最大 sort_buffer_size/连接)
#   join_buffer_size
#   read_buffer_size
#
# 估算总使用:
#   固定部分 + max_connections × 每连接估算

# 简单估算脚本
mysql -u root -p -e "
SELECT
  @@innodb_buffer_pool_size / 1024 / 1024 / 1024 AS buffer_pool_GB,
  @@max_connections AS max_conn,
  ROUND(@@max_connections * (@@sort_buffer_size + @@join_buffer_size + @@read_buffer_size) / 1024 / 1024 / 1024, 2) AS conn_mem_GB
\G"

3. 连接与线程配置

# ==========================================
# 连接配置
# ==========================================

# 最大连接数
max_connections       = 1000
# 注意:不是越大越好,每个连接消耗内存,且线程切换有开销
# 公式:max_connections ≈ (可用内存 - 固定内存) / 单连接内存
# 建议:不超过 2000,超过考虑 ProxySQL 连接池

# 超级用户保留连接数(保证管理员能连上)
max_user_connections  = 950   # 普通用户最大连接数
# max_connections - max_user_connections 保留给 SUPER 权限用户

# 待连接队列大小(SYN 队列)
back_log              = 1000   # 高并发下需要增大

# ==========================================
# 超时配置(非常重要!避免连接泄漏)
# ==========================================

# 非交互连接(程序连接)的空闲超时
wait_timeout          = 600    # 秒,默认 28800(8小时)太长
# 建议:比应用层连接池的 MaxLifetime 大,比如设 600s

# 交互连接(mysql 命令行)的空闲超时
interactive_timeout   = 600

# 连接建立超时(网络层)
connect_timeout       = 10

# 等待锁的超时
innodb_lock_wait_timeout = 10  # 默认 50s,太长

# 慢查询超时(不是真的超时,只是记录)
long_query_time       = 1      # 超过 1s 记录慢查询

# ==========================================
# 线程配置
# ==========================================

# 线程缓存(减少频繁创建/销毁线程的开销)
thread_cache_size     = 100
# 监控:Threads_created 状态变量,增长快则增大 thread_cache_size

# 线程栈大小(每个线程的栈内存)
thread_stack          = 512K   # 默认 1M,可以适当减小

# 并发线程控制(InnoDB 层)
innodb_thread_concurrency = 0  # 0=不限制(默认),或设为 CPU 核数×2

4. InnoDB 核心配置

# ==========================================
# InnoDB 存储
# ==========================================

# 每表独立表空间(强烈推荐)
innodb_file_per_table = ON

# 系统表空间初始大小(不重要,innodb_file_per_table=ON 后数据在各自 .ibd)
innodb_data_file_path = ibdata1:12M:autoextend

# 临时表空间
innodb_temp_data_file_path = ibtmp1:12M:autoextend:max:5G

# Double Write Buffer(防止部分写,必须开)
innodb_doublewrite = ON

# ==========================================
# InnoDB I/O 配置
# ==========================================

# 后台 I/O 线程数(读/写线程各自数量)
innodb_read_io_threads  = 4   # 默认 4,SSD 可以调大
innodb_write_io_threads = 4

# 最大每秒 I/O 操作数(IOPS 限制)
innodb_io_capacity      = 200   # HDD: 200, SSD: 2000~10000
innodb_io_capacity_max  = 400   # 紧急刷盘时的最大 IOPS,通常设 2×io_capacity

# 刷新脏页的算法
innodb_flush_method     = O_DIRECT   # 绕过 OS 缓存(推荐,避免双重缓存)
                                      # Windows 用 normal

# ==========================================
# InnoDB Redo Log
# ==========================================

# MySQL 8.0.30 以前
innodb_log_file_size    = 256M     # 每个文件大小(推荐 256M~2G)
innodb_log_files_in_group = 2      # 文件数量

# MySQL 8.0.30+(推荐使用这个)
innodb_redo_log_capacity = 1G      # 总大小

# 刷盘策略(最关键!)
innodb_flush_log_at_trx_commit = 1  # 1=最安全,0/2=高性能但有丢失风险

# Redo Log Buffer 大小
innodb_log_buffer_size  = 64M     # 默认 16M,大事务可以调大

# ==========================================
# InnoDB 行锁与事务
# ==========================================

# 行锁等待超时
innodb_lock_wait_timeout = 10

# 死锁检测(高并发可关闭,改用超时)
innodb_deadlock_detect   = ON

# Rollback 段数量(并发事务多时增大)
innodb_rollback_segments = 128    # 默认 128,最大 128

# ==========================================
# InnoDB 统计信息
# ==========================================

# 持久化统计信息(重启后不需要重新计算)
innodb_stats_persistent = ON
innodb_stats_persistent_sample_pages = 20  # 采样页数,越大越准确但越慢

# 自动更新统计信息(数据变化超过 10% 时)
innodb_stats_auto_recalc = ON

# ==========================================
# InnoDB Change Buffer
# ==========================================

# 写缓冲最大占 Buffer Pool 的比例
innodb_change_buffer_max_size = 25  # 默认 25%,读多写少可降低,写多可增大

# ==========================================
# 表打开缓存
# ==========================================

# 文件描述符缓存(表越多设越大)
table_open_cache       = 4000
table_definition_cache = 2000
open_files_limit       = 65535  # OS 级别的文件描述符限制

5. 日志配置

# ==========================================
# Binlog
# ==========================================

log_bin              = mysql-bin
binlog_format        = ROW
binlog_row_image     = MINIMAL          # 只记录变更的列,减少日志量
max_binlog_size      = 1G
binlog_expire_logs_seconds = 604800     # 7天(MySQL 8.0)
expire_logs_days     = 7               # 7天(MySQL 5.7)
sync_binlog          = 1               # 每次提交都 fsync(最安全)

# Binlog 校验
binlog_checksum      = CRC32            # 校验和(防止传输损坏)

# ==========================================
# 慢查询日志
# ==========================================

slow_query_log          = ON
slow_query_log_file     = /var/log/mysql/slow.log
long_query_time         = 1             # 超过 1 秒记录
log_queries_not_using_indexes = ON      # 未用索引的查询也记录
log_throttle_queries_not_using_indexes = 10  # 每分钟最多记录 10 条
min_examined_row_limit  = 100           # 扫描行数少于 100 不记录

# ==========================================
# 错误日志
# ==========================================

log_error            = /var/log/mysql/error.log
log_error_verbosity  = 2               # 2=错误+警告

# ==========================================
# 通用查询日志(调试用,一般关闭)
# ==========================================

general_log          = OFF
general_log_file     = /var/log/mysql/general.log

6. 复制配置

# ==========================================
# 通用复制配置
# ==========================================

server_id            = 1               # 每台服务器唯一 ID
log_bin              = mysql-bin
log_slave_updates    = ON              # 从库的变更也写 Binlog(级联复制/MGR必须)
relay_log            = relay-bin
relay_log_purge      = ON
relay_log_recovery   = ON             # 崩溃恢复重新获取 Relay Log

# ==========================================
# GTID 配置(强烈推荐)
# ==========================================

gtid_mode            = ON
enforce_gtid_consistency = ON

# ==========================================
# 主库配置
# ==========================================

binlog_format        = ROW
sync_binlog          = 1

# 半同步复制(可选)
# rpl_semi_sync_master_enabled = 1
# rpl_semi_sync_master_timeout = 1000

# ==========================================
# 从库配置
# ==========================================

read_only            = ON
super_read_only      = ON             # 防止 super 用户写

# 并行复制(提升从库吞吐)
slave_parallel_type     = LOGICAL_CLOCK
slave_parallel_workers  = 8
slave_preserve_commit_order = ON      # 保持事务提交顺序(避免数据不一致)

# 复制过滤(按需配置)
# replicate_do_db       = myapp       # 只复制指定库
# replicate_ignore_table = myapp.cache_table  # 忽略某张表

# 主从信息存储方式(推荐 TABLE,避免文件损坏)
master_info_repository   = TABLE
relay_log_info_repository = TABLE

7. 安全配置

# ==========================================
# 网络安全
# ==========================================

# 绑定地址(不要绑定 0.0.0.0 除非必要)
bind_address         = 0.0.0.0   # 生产建议改为具体 IP 或只开内网
port                 = 3306

# SSL/TLS(MySQL 8.0 默认开启)
ssl_ca               = /etc/mysql/ssl/ca.pem
ssl_cert             = /etc/mysql/ssl/server-cert.pem
ssl_key              = /etc/mysql/ssl/server-key.pem
# require_secure_transport = ON  # 强制所有连接使用 SSL

# ==========================================
# SQL 安全
# ==========================================

# 防止误操作(没有 WHERE 的 UPDATE/DELETE 会报错)
sql_safe_updates     = ON   # 建议在应用测试/开发开启

# 禁用 LOCAL INFILE(防止文件读取攻击)
local_infile         = OFF

# 禁止符号链接(防止权限绕过)
symbolic_links       = OFF

# 密码策略
# validate_password.policy = MEDIUM   # MySQL 8.0 默认
# validate_password.length = 8

# ==========================================
# 文件系统安全
# ==========================================

# 限制 LOAD DATA 和 SELECT ... INTO OUTFILE 的目录
secure_file_priv     = /tmp   # 或设为空字符串禁止,或指定目录

# ==========================================
# 账号安全
# ==========================================

# 失败登录锁定(MySQL 8.0.19+)
# CREATE USER 'app'@'%' IDENTIFIED BY '...'
#   FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LOCK_TIME 1;

8. SQL Mode

# SQL Mode 控制 MySQL 的行为和数据校验严格程度
sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"

8.1 重要 Mode 说明

Mode 说明
STRICT_TRANS_TABLES 事务表(InnoDB)严格模式:无效数据直接报错,不自动截断/转换
STRICT_ALL_TABLES 所有表严格模式(包括 MyISAM)
NO_ZERO_DATE 不允许 ‘0000-00-00’ 格式日期
NO_ZERO_IN_DATE 不允许月或日为 0 的日期(如 ‘2024-00-01’)
ERROR_FOR_DIVISION_BY_ZERO 除以 0 时报错(而非返回 NULL)
NO_ENGINE_SUBSTITUTION 指定引擎不可用时报错(而非换用默认引擎)
ONLY_FULL_GROUP_BY GROUP BY 严格模式(MySQL 5.7.5+ 默认开启)
ANSI_QUOTES " 用于标识符而非字符串(影响 SQL 兼容性)
PIPES_AS_CONCAT `
-- 查看当前 SQL Mode
SELECT @@sql_mode;
SHOW VARIABLES LIKE 'sql_mode';

-- 会话级别修改
SET SESSION sql_mode = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO';

-- 临时关闭 ONLY_FULL_GROUP_BY(迁移时临时用)
SET SESSION sql_mode = sys.list_drop(@@SESSION.sql_mode, 'ONLY_FULL_GROUP_BY');

9. 性能 Schema 配置

# performance_schema 开启(默认 ON)
performance_schema = ON

# 控制内存占用
performance_schema_max_table_instances = 12500
performance_schema_max_table_handles = 40000
-- 查看 performance_schema 内存使用
SELECT SUM_NUMBER_OF_BYTES_ALLOC / 1024 / 1024 AS mb
FROM performance_schema.memory_summary_global_by_event_name
WHERE EVENT_NAME = 'memory/performance_schema/table_shares';

-- 启用/禁用特定监控
UPDATE performance_schema.setup_instruments
SET ENABLED = 'YES', TIMED = 'YES'
WHERE NAME LIKE 'statement/%';

UPDATE performance_schema.setup_consumers
SET ENABLED = 'YES'
WHERE NAME LIKE 'events_statements%';

10. 生产推荐配置模板

# ==========================================
# 生产环境 MySQL 8.0 配置模板
# 机器规格:8 核 16GB 内存
# ==========================================

[mysqld]
# ---- 基础 ----
user             = mysql
basedir          = /usr/local/mysql
datadir          = /data/mysql
socket           = /tmp/mysql.sock
pid_file         = /data/mysql/mysql.pid
port             = 3306
server_id        = 1

# ---- 字符集 ----
character_set_server     = utf8mb4
collation_server         = utf8mb4_unicode_ci
init_connect             = 'SET NAMES utf8mb4'

# ---- 时区 ----
default_time_zone        = '+8:00'

# ---- 连接 ----
max_connections          = 1000
max_user_connections     = 950
back_log                 = 1000
wait_timeout             = 600
interactive_timeout      = 600
connect_timeout          = 10
thread_cache_size        = 100

# ---- 内存 ----
innodb_buffer_pool_size     = 10G         # 16G * 62.5%
innodb_buffer_pool_instances = 8
innodb_buffer_pool_load_at_startup  = ON
innodb_buffer_pool_dump_at_shutdown = ON
innodb_buffer_pool_dump_pct         = 25
sort_buffer_size            = 2M
join_buffer_size            = 2M
tmp_table_size              = 64M
max_heap_table_size         = 64M
thread_stack                = 512K

# ---- InnoDB I/O ----
innodb_file_per_table        = ON
innodb_flush_method          = O_DIRECT
innodb_read_io_threads       = 8          # SSD 适当调大
innodb_write_io_threads      = 8
innodb_io_capacity           = 4000       # SSD
innodb_io_capacity_max       = 8000
innodb_doublewrite           = ON

# ---- InnoDB Redo Log ----
innodb_redo_log_capacity     = 2G         # MySQL 8.0.30+
innodb_flush_log_at_trx_commit = 1        # 双 1 配置
innodb_log_buffer_size       = 64M

# ---- InnoDB 事务 ----
innodb_lock_wait_timeout     = 10
innodb_deadlock_detect       = ON
innodb_stats_persistent      = ON
innodb_stats_auto_recalc     = ON

# ---- 表缓存 ----
table_open_cache             = 4000
table_definition_cache       = 2000
open_files_limit             = 65535

# ---- Binlog ----
log_bin                      = /data/binlog/mysql-bin
binlog_format                = ROW
binlog_row_image             = MINIMAL
max_binlog_size              = 1G
binlog_expire_logs_seconds   = 604800     # 7 天
sync_binlog                  = 1          # 双 1 配置
binlog_checksum              = CRC32
binlog_cache_size            = 2M

# ---- 慢查询 ----
slow_query_log               = ON
slow_query_log_file          = /data/mysql/slow.log
long_query_time              = 1
log_queries_not_using_indexes = ON
log_throttle_queries_not_using_indexes = 10
min_examined_row_limit       = 100

# ---- 错误日志 ----
log_error                    = /data/mysql/error.log
log_error_verbosity          = 2

# ---- GTID 复制 ----
gtid_mode                    = ON
enforce_gtid_consistency     = ON
log_slave_updates            = ON
relay_log                    = /data/relaylog/relay-bin
relay_log_purge              = ON
relay_log_recovery           = ON
master_info_repository       = TABLE
relay_log_info_repository    = TABLE

# ---- SQL Mode ----
sql_mode                     = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"

# ---- 安全 ----
local_infile                 = OFF
symbolic_links               = OFF
secure_file_priv             = /tmp

# ---- performance_schema ----
performance_schema           = ON

[mysql]
prompt                       = 'MySQL [\d]> '
no_auto_rehash

[client]
port                         = 3306
socket                       = /tmp/mysql.sock
default_character_set        = utf8mb4

10.1 配置验证

# 语法检查(不启动服务)
mysqld --defaults-file=/etc/my.cnf --validate-config

# 查看所有非默认值配置
mysqld --print-defaults
-- 启动后检查关键参数
SELECT
  VARIABLE_NAME, VARIABLE_VALUE
FROM performance_schema.global_variables
WHERE VARIABLE_NAME IN (
  'innodb_buffer_pool_size',
  'max_connections',
  'innodb_flush_log_at_trx_commit',
  'sync_binlog',
  'binlog_format',
  'gtid_mode',
  'transaction_isolation',
  'sql_mode'
)
ORDER BY VARIABLE_NAME;

小结

关键配置记忆口诀:

双1配置保数据安全:
  innodb_flush_log_at_trx_commit = 1
  sync_binlog = 1

内存三大件:
  innodb_buffer_pool_size = 物理内存 60~80%
  tmp_table_size = max_heap_table_size(一致)
  sort_buffer/join_buffer 适度(别设太大)

连接别忘超时:
  wait_timeout(连接空闲超时)
  innodb_lock_wait_timeout(锁等待超时)

日志开够:
  binlog(主从/恢复)
  slow_query_log(性能分析)
  error_log(故障排查)