MySQL时区需在my.cnf的[mysqld]段用default-time-zone显式配置并重启生效,server_time_zone为只读且由启动时决定;字符集须同时设character-set-server和collation-server,并确保连接与存量对象同步更新。

MySQL 启动时如何正确设置时区(server_time_zone)
MySQL 的时区不是靠操作系统时区自动同步的,server_time_zone 默认是 SYSTEM,意味着它会读取 mysqld 启动时的系统时区(不是当前 shell 的 TZ 环境变量),且启动后不可动态修改。如果你看到 SELECT NOW() 和系统时间对不上,大概率是这里没设对。
- 最稳妥的方式是在配置文件
/etc/my.cnf或/etc/mysql/my.cnf的[mysqld]段下显式指定:[mysqld] default-time-zone = '+08:00'
或用命名时区(需系统支持):default-time-zone = 'Asia/Shanghai'
- 注意:
default-time-zone影响的是新连接的time_zone会话变量,默认值;而server_time_zone是只读的服务器级时区,由default-time-zone或启动时推导决定,不能 SET - 改完必须重启 mysqld,
SET GLOBAL time_zone只影响后续新连接的默认会话时区,不改变server_time_zone - 验证方式:
SELECT @@global.time_zone, @@session.time_zone, @@global.system_time_zone;—— 三个值要分清:前两个可设,最后一个只读且等于启动时的系统时区或default-time-zone值
哪些 MySQL 系统参数必须在 my.cnf 里配,不能用 SET GLOBAL
很多关键参数属于「只读启动参数」,运行时无法修改,比如内存类、日志路径、字符集基础项。强行 SET GLOBAL 会报错 ERROR 1238 (HY000): Variable 'xxx' is a read only variable。
- 典型只读参数:
innodb_data_home_dir、datadir、log_bin、character-set-server、collation-server、max_connections(MySQL 5.7+ 可动态调高但不能低于当前活跃连接数)、innodb_buffer_pool_size(8.0.22+ 支持在线调整,但有上下限限制) -
wait_timeout、max_allowed_packet、sort_buffer_size这类可以SET GLOBAL,但仅对之后的新连接生效,当前连接不变 - 修改
my.cnf后记得检查语法:mysqld --defaults-file=/etc/my.cnf --validate-config,避免重启失败
character-set-server 和 collation-server 配置陷阱
光设 character-set-server = utf8mb4 不够,MySQL 5.7+ 默认 collation-server 是 utf8mb4_general_ci,但这个排序规则不区分 emoji 和部分四字节字符的比较逻辑,推荐用 utf8mb4_0900_as_cs(8.0+)或 utf8mb4_unicode_ci(5.7)。更关键的是:如果客户端连接时没声明 charset=utf8mb4,或者建表没指定 CHARACTER SET,依然可能存成 latin1。
- my.cnf 必须同时写两行:
character-set-server = utf8mb4 collation-server = utf8mb4_0900_as_cs
- 连接字符串里要显式加
?charset=utf8mb4(如 Python 的 pymysql、Java 的 JDBC) - 已有库/表需手动转换:
ALTER DATABASE db_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_as_cs;,表和字段同理,否则配置只是「默认」,不改变存量 - 验证是否生效:
SHOW VARIABLES LIKE 'character_set%'; SHOW VARIABLES LIKE 'collation%';,重点看character_set_server和collation_server
配置修改后为什么 SHOW VARIABLES 不立即反映?
因为 SHOW VARIABLES 显示的是当前会话生效的值,而很多参数(尤其是只读参数)修改后必须重启 mysqld 才能加载。即使你改了 my.cnf 并执行了 systemctl restart mysql,也有可能没真正加载到新配置。
- 确认 mysqld 实际读取的是哪个配置文件:
mysqld --verbose --help | grep "Default options",常见路径还有/usr/my.cnf、~/.my.cnf,优先级高于 /etc/my.cnf - 检查启动时有没有警告:
sudo journalctl -u mysql -n 50 --no-pager,留意unknown variable或deprecated提示(比如老版本用default-character-set,新版本已废弃) - 某些参数(如
sql_mode)支持动态设置,但若在 my.cnf 里写了错误值(例如多加了个空格),会导致整个配置段被跳过,而不是只忽略那一行
mysqld --help --verbose 看实际支持什么。


















