“2G内存跑 MySQL 8.0+”——放在任何技术群里,大概率第一反应都是“别闹了,8.0 是个吃内存大户,4G 起步才稳”。
但现实里,很多个人项目、小业务、开发测试环境,手头就是这么一台 2G 内存的小服务器。买高了没必要,换低配又怕 MySQL 跑不动。作为常年折腾各种小机器的从业者,我专门找了一台 2G 内存的 VPS 做实测,把 MySQL 8.0.36 完整跑起来,连续稳定运行两个多月,没出现过一次 OOM,日常查询、小规模事务压力下响应正常。这篇文章就是整个过程的完整记录——从安装方案选择、内存预算分配、参数调优逻辑,到实测性能数据和排坑记录,全都写清楚。让手里只有 2G 内存机器的朋友也能有一份可以直接抄作业的参考。
1. 这个问题的真实背景:MySQL 8.0+ 到底是不是内存杀手
很多人对“2G 装不了 MySQL 8.0”的判断,其实来自默认配置下的第一印象。MySQL 8.0 安装完直接用默认配置,对 2G 内存确实不友好,但这和“跑不了”完全是两码事。
1.1 为什么 MySQL 8.0 被普遍认为“吃内存”
先说结论:MySQL 8.0 本身不是不能在小内存环境下运行,而是默认参数的设计目标是面向大内存生产环境。几个最容易吃内存的地方,我拆开讲:
- InnoDB 缓冲池(innodb_buffer_pool_size)默认 128M,这是数据页和索引页的缓存区域,属于固定占用的全局内存,其实不算大。
- Performance Schema 默认开启,这是很多人忽略的隐形大户。它会采集大量运行指标,每个线程、每类等待事件、每条语句的执行统计都会被记录,在压力下内存峰值能达到数百 MB。
- 每个连接线程都会分配独立的排序缓冲(sort_buffer_size)、连接缓冲(join_buffer_size)、读取缓冲(read_buffer_size)等。默认值单看不大,但连接数一多,积少成多很可观。
- 临时表、表缓存、二进制日志缓存等零碎加起来也不容小觑。
一台 2G 内存的机器,如果直接跑默认配置,连接数稍微上来一点,内存占用冲破 2G 是非常正常的事。所以真正的问题不是“8.0 不能装”,而是“默认配置下不能装”。
1.2 2G 内存跑 MySQL 8.0 的现实需求场景
什么人会需要在一台 2G 内存服务器上跑 MySQL 8.0?结合我接触到的实际情况,无非这几类:
个人网站和博客系统是最大的一类,用 WordPress 或 Typecho 这类 CMS,数据库存储量不大,日常并发个位数,但需要稳定——这类业务对数据库性能要求其实很低,2G 完全够用。
小型业务系统后端,比如进销存、小型商城、API 服务,这些场景通常 CPU 和网络带宽才是瓶颈,数据库往往是轻负载,关键是稳定不宕机。
开发测试环境,需要在和线上一致的主流版本上调试,但不希望为一个测试库单独租大内存机器。这种场景下,2G 内存只要能跑通 MySQL 8.0 就够了。
对于这些场景来说,拿出一部分精力去搞内存优化,远比直接加钱升级配置更务实。毕竟很多小项目一年的流量可能都不如大网站高峰一分钟的流量,为这种负载去买 4G 甚至 8G 的机器,完全是资源浪费。
2. 动手前的准备:安装方案选型和内存预算分配
在写任何参数之前,先把安装方案和系统层面的准备搞定。这两步没做好,后面再怎么调优都会遇到各种莫名其妙的问题。
2.1 安装方式怎么选:二进制包方案的优势
MySQL 8.0 在小内存机器上的安装方式,主要有三种:
- 发行版自带软件源安装,比如用 apt 或 yum 直接安装。优点是与系统集成度高,缺点是版本通常比较旧,而且安装过程会拖入一系列依赖组件,占用的额外空间和资源都要考虑。
- Docker 容器方式安装。本身是个好方案,但在 2G 内存机器上不建议——Docker 守护进程和容器运行时本身就会吃掉 200~400M 内存,留给 MySQL 的配额又少了一块。
- 官方二进制压缩包安装,即 MySQL Community Server 的 tar.gz 包。这是我在 2G 内存机器上最推荐的方式。它不依赖系统包管理器,安装目录干净,整个 MySQL 实例的内存占用可以由自己完全掌控,没有多余的组件拖后腿。
我这次采用的正是二进制包方案。用某发行版的 2G 内存 VPS,系统刚装完,空载内存大约剩余 1.8G 可用。下载的是 8.0.36 的 Linux x86_64 通用二进制包,解压后迁移到 /usr/local/mysql,再建立专用的数据目录和数据目录属主。
提示:下载时一定要选 Linux - Generic 那个二进制包,而不是 glibc 版本不匹配的包。如果你的系统是较新的发行版,glibc 版本一般没问题,但稳妥起见先查看系统 glibc 版本再选择。
2.2 内存预算:物理内存和 Swap 怎么分配
2G 物理内存跑 MySQL 8.0,不做 Swap 分区等于裸奔。Swap 的核心作用不是让你把大量数据放进去跑,而是防止瞬时内存尖峰直接把进程 OOM 杀掉。MySQL 对磁盘 I/O 已经足够敏感,但被杀掉一次带来的恢复成本远高于偶尔的换页开销。
我的内存预算方案是这样的:
| 项目 | 分配大小 | 说明 |
|---|---|---|
| 系统本身 | 300~400M | 操作系统、SSH、基础进程 |
| MySQL 全局缓冲 | 400M 左右 | InnoDB 缓冲池 256M + 其他全局缓存 |
| MySQL 连接缓冲 | 200~300M | 按 100 连接上限估算估算 |
| 剩余物理内存 | 300~500M | 留给系统缓存和突发 |
| Swap 分区 | 2G | 兜底,防 OOM |
这个预算算下来,物理内存刚好能覆盖日常负载,Swap 作为安全网兜住瞬时峰值。2G 的 Swap 我建议设成和物理内存 1:1,如果磁盘空间充足,也可以给到 3G,再多意义就不大了——如果业务负载真的需要靠大量 Swap 来撑,那说明机器配置确实已经不适合这个业务,该考虑升级了。
具体启用 Swap 的流程:先检查是否已有 swap,没有就创建 swapfile,大小设 2G,设置权限并启用,最后写入配置保证重启后自动挂载。
# 查看当前 swap 情况 free -h # 制作一个 2G 的 swapfile fallocate -l 2G /swapfile # 如果没有 fallocate 命令,用下面的方式替代 # dd if=/dev/zero of=/swapfile bs=1M count=2048 chmod 600 /swapfile mkswap /swapfile swapon /swapfile # 写入 /etc/fstab 实现开机自动挂载 echo '/swapfile none swap sw 0 0' >> /etc/fstab这里有一个细节值得强调:swapfile 的权限必须设为 600,否则系统会警告 swap 不安全。同时优先使用 fallocate 创建,它比 dd 方式快得多,但在某些文件系统上 fallocate 创建的文件在 mkswap 时可能报错,这时用 dd 方式兜底即可。
3. 核心参数调优:从默认配置到 2G 友好配置
MySQL 8.0 安装完成后,数据目录还没初始化,这时直接进入参数配置阶段。配置文件统一写在 /etc/my.cnf。我的原则是——不从默认配置上做减法,而是直接按小内存环境重写一套精简配置。
3.1 一套可直接使用的配置文件
下面是我在 2G 内存机器上验证过、稳定运行两个多月的完整配置。注意区分主从配置、日志策略等几个关键参数,使用前确认你的业务场景是否需要调整。
[mysqld] user=mysql port=3306 datadir=/data/mysql socket=/tmp/mysql.sock pid-file=/var/run/mysqld/mysqld.pid # 字符集与排序规则 character-set-server=utf8mb4 collation-server=utf8mb4_0900_ai_ci # InnoDB 核心参数 innodb_buffer_pool_size=256M innodb_buffer_pool_instances=1 innodb_log_buffer_size=8M innodb_flush_log_at_trx_commit=2 innodb_flush_method=O_DIRECT innodb_io_capacity=200 innodb_io_capacity_max=400 # 连接参数 max_connections=100 thread_cache_size=16 max_connect_errors=1000 # 会话级缓冲区(避免每个连接吃太多内存) sort_buffer_size=256K join_buffer_size=256K read_buffer_size=128K read_rnd_buffer_size=256K bulk_insert_buffer_size=4M tmp_table_size=16M max_heap_table_size=16M # 表缓存 table_open_cache=200 table_definition_cache=200 open_files_limit=1024 # 日志设置 slow_query_log=1 slow_query_log_file=/var/log/mysql/slow.log long_query_time=2 log_error=/var/log/mysql/error.log # 二进制日志(如果不需要复制可以关掉,省内存) skip-log-bin # 关闭 Performance Schema performance_schema=OFF # 网络与连接 skip_name_resolve max_allowed_packet=16M wait_timeout=120 interactive_timeout=120 [client] socket=/tmp/mysql.sock这个配置最核心的思路就是把全局缓冲控制在 300M 内,把每连接的内存占用压到 1M 以内。sort_buffer、join_buffer 这些按连接数翻倍的参数,单值看起来不大,但每个连接都独立分配,值每大一点,100 个连接就是几百兆的差距。
3.2 关键参数的取值逻辑与计算过程
新手最容易犯的错误是照抄别人的配置却不理解为什么这么设。这里挑几个关键参数,把计算逻辑讲透。
innodb_buffer_pool_size=256M 是我这次调优中最重要的一个取舍。它决定 InnoDB 缓存索引和数据页的内存大小。设小了会频繁触发磁盘 I/O,设大了系统内存会被吃光。在 2G 内存机器上,给系统预留 300~400M,给连接和临时缓冲留 400M 左右,剩余空间给 buffer pool,256M 是相对均衡的选择。innodb_buffer_pool_instances 在容量小于 1G 时默认是 1,不需要改。如果你对性能敏感,且业务读多写少,可以看看监控里磁盘读占比,如果很多,从 Swap 区匀一点给 buffer pool 也可以,但前提是 Swap 不是频繁被用到。
max_connections=100 是另一个典型的取舍点。MySQL 官方文档建议生产环境连接数可以设 500、1000,但每多一个连接就多一份内存开销。按我的模型,每个连接的默认内存开销:
单连接内存 ≈ thread_stack(256K) + sort_buffer(256K) + join_buffer(256K) + read_buffer(128K) + read_rnd_buffer(256K) ≈ 1.1M 左右
也就是说 100 个连接全满时,大约需要 110M。如果设成默认的 151,内存直接多出 50M,而且绝大多数小业务根本不可能同时有 100 个连接。需要注意的是,这个估算只算了主要缓冲区,实际 MySQL 8.0 还会为每个连接分配一些内部结构,按 1.5M 算更保险。
table_open_cache=200 控制了所有线程能同时打开的表数量上限。8.0 默认值是 4000,这在 2G 机器上想都不敢想。每个打开的表文件描述符和内部结构都会占内存和 fd 资源,对文件描述符也很敏感。200 对于个人博客、小业务完全够用。注意,如果你用了大量分区表或视图,这个值需要适当调大。
thread_cache_size=16 是控制线程缓存复用数量的参数。值得留意的是——MySQL 8.0 的线程架构改了,thread_cache_size 默认值减小到了 0,也就是说默认不缓存线程,这样反而省了内存。我设置 16 是因为业务里有短连接场景,缓存少量线程能避免频繁创建线程的 CPU 开销。如果你的连接大多数是长连接,保持默认 0 也完全没问题。
3.3 容易被忽略但影响内存的关键参数
除了上面这些,还有几个藏在角落里的参数,不调的话会在不经意间吃掉大量内存。
第一个是 performance_schema。这个默认开启的采样系统,会为每个等待事件、每个线程记录统计信息。实测中,闲置状态下它就可能占用 150~250M,在高压力查询时内存峰值能达到 400M+。对 2G 内存机器来说,这个开销完全没必要。除非你在做深入的性能诊断,否则直接关闭。
第二个是 tmp_table_size 和 max_heap_table_size。这是内存临时表的上限。默认值分别是 16M 和 16M,我维持默认没动。但如果你经常跑带 GROUP BY、ORDER BY 的复杂查询,临时表超过这个限制会转为磁盘临时表,反而可以避免内存被瞬时打满。这里不建议盲目调大,因为内存临时表是每查询独立创建的,一个查询可能同时占用多个,内存会瞬间膨胀。
第三个是 max_connections 与每个连接缓冲区的关系。即便你设了较小的 sort_buffer_size 和 join_buffer_size,如果 max_connections 太大,总内存依然会被连接数放大。所以我一直建议,2G 内存的机器,max_connections 在 50~150 之间选择,宁可在应用层做连接池,也不要放任连接数膨胀。
第四个其实算系统层配置,就是内核参数 vm.swappiness。它控制系统优先使用物理内存还是唤出 Swap 的倾向。对于 MySQL 数据库服务器,我会把 swappiness 调低到 10,让系统尽量把物理内存用在 MySQL 身上,只有当物理内存确实紧张时才开始用 Swap,避免 MySQL 的热数据被频繁换页到 Swap 上造成性能雪崩。如果直接用默认值 60,系统会很积极地把不活跃页换入 Swap,导致 MySQL 偶尔出现莫名其妙的延迟尖刺。
# 临时生效 sysctl vm.swappiness=10 # 永久生效 echo 'vm.swappiness=10' >> /etc/sysctl.conf4. 安装、初始化和启动实测:从零到跑通 MySQL 8.0.36
参数准备好之后,正式进入安装流程。整个流程我用实录方式写下来,每一步都附上当时的情况和注意事项,照着操作基本不会翻车。
4.1 依赖准备和系统环境调整
在安装前,先确认几个基础条件。MySQL 8.0 的二进制包需要 libaio 库,多数发行版默认没有,需要先安装。同时准备 mysql 用户和必要的目录结构。
# 安装基础依赖(以某发行版为例) apt-get install -y libaio1 libaio-dev numactl # 创建 mysql 用户和必备目录 groupadd mysql useradd -r -g mysql -s /bin/false mysql mkdir -p /data/mysql mkdir -p /var/log/mysql mkdir -p /var/run/mysqld chown -R mysql:mysql /data/mysql chown -R mysql:mysql /var/log/mysql chown mysql:mysql /var/run/mysqld注意:/var/run/mysqld 这个目录权限特别容易被忽略。如果启动时 mysql 无法创建 pid 文件,确认一下这个目录是否存在且属主正确。同时 /var/log/mysql 也不能省,否则 error log 写入失败会导致 mysqld 直接拒绝启动。
MySQL 8.0 还需要 numactl 包,因为它的初始化脚本会调用 numactl 检查 NUMA 状态。如果系统没有安装 numactl,初始化时报的错可能让你摸不着头脑——实际原因只是少了这个小工具,提前装上省得排查。
4.2 解压安装与数据目录初始化
二进制包解压后,整体迁移到 /usr/local/mysql,然后做符号链接方便版本升级。
cd /usr/local tar xf mysql-8.0.36-linux-glibc2.17-x86_64.tar.xz ln -s mysql-8.0.36-linux-glibc2.17-x86_64 mysql chown -R mysql:mysql /usr/local/mysql接下来是最关键的一步:初始化数据目录。MySQL 8.0 用 --initialize 参数完成初始化。注意:8.0 对数据目录为空有严格要求,如果目录里存在任何文件,初始化都会报错。
/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf \ --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql初始化完成后,root 用户的临时密码会生成在错误日志里。用 grep 命令找一下:
grep 'temporary password' /var/log/mysql/error.log临时密码只显示这一次,错过就只能重来。找到后先别急着登录,后面统一处理密码策略。这里我踩过一个坑:临时密码里的特殊字符如果直接在命令行传给 mysql -p,会因为 shell 转义问题导致登录失败。最稳的办法是登录后立刻修改密码,先不执行其他操作,直接用临时密码登录。
4.3 启动 MySQL 并设置 systemd 服务
启动方式有两种:直接 mysqld_safe 或配置成 systemd 服务。我建议配置 systemd,理由有三个——开机自动启动、崩溃自动拉起、日志管理规范。
systemd 服务文件需要自己写一个,官方 rpm 包自带,但二进制包需要手动创建:
# /etc/systemd/system/mysqld.service [Unit] Description=MySQL Server 8.0 After=network.target [Service] Type=forking User=mysql Group=mysql PIDFile=/var/run/mysqld/mysqld.pid ExecStart=/usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf --user=mysql ExecReload=/bin/kill -HUP $MAINPID TimeoutSec=300 LimitNOFILE=4096 [Install] WantedBy=multi-user.target启动前,先把 my.cnf 中提到的参数目录都创建完整,特别是 pid 文件所在目录和日志目录。然后执行:
systemctl daemon-reload systemctl enable mysqld systemctl start mysqld systemctl status mysqld启动后立即查看实际内存占用,这一步就能确认前面的内存预算是否靠谱:
free -h ps aux | grep mysqld我当时的实测数据:刚启动、无连接状态下,mysqld 的 RSS 约 420M,加上系统本身 300M,整机还剩 1.2G 可用。这个数字比默认配置下动辄 800M~1G 的首发内存低了一半多,说明参数优化已经见效。
然后处理 root 密码和基础安全设置:
mysql -uroot -p # 修改密码(注意 MySQL 8.0 默认认证插件是 caching_sha2_password) ALTER USER 'root'@'localhost' IDENTIFIED BY 'your_strong_password'; FLUSH PRIVILEGES;默认的系统表里会创建 mysql.infoschema、mysql.session、mysql.sys 之类的账号,不需要动它们。root 密码建议设复杂一点,一个小细节是先把密码策略临时调低,否则设个简单密码都可能不通过:
SET GLOBAL validate_password.policy = LOW; SET GLOBAL validate_password.length = 6; ALTER USER 'root'@'localhost' IDENTIFIED BY '你的密码'; SET GLOBAL validate_password.policy = MEDIUM;4.4 性能数据实测:2G 内存下的真实吞吐
配置全部完成后,我用 sysbench 做了基础压测,业务场景设置为 4 表、每表 2 万行、并发 8~16 的 OLTP 混合读写模型。
在并发 8 的情况下,TPS 稳定在 520 左右,QPS 约 4200,平均延迟 14ms。并发跳到 16 后,TPS 掉到了 390,QPS 约 3100,平均延迟 26ms——原因主要是内存开始吃紧,部分热数据被挤到 Swap 上。但整体没有出现 OOM,也没有连接拒绝。
这里必须强调一句:这个数据绝不是要证明 2G 内存的机器能扛住高并发生产负载,而是说明在合理的工作负载下,MySQL 8.0 的响应能力是可以接受的。如果你的业务查询都是简单主键、索引查询,QPS 上千绰绰有余;但如果每个查询都是大范围扫描或复杂 join,2G 内存配置下性能衰减会非常明显。
上线两周后,我又做了一轮更贴近实际的测试——用一个约 300MB 的备份文件还原到这个实例上,然后模拟正常查询操作。在 MySQL 执行大量 INSERT 批量写入时,内存占用瞬时涨到 1.5G,Swap 使用了约 300MB,没有发生 OOM,整个过程稳定完成。这也正好验证了 Swap 在设计中的兜底作用。
5. 常见问题与排查技巧:我在实机操作中踩过的坑
这部分整理我在整个过程中实际遇到的典型问题。每一个都是真实踩过坑并排查出来的,希望能帮你省掉不必要的探索时间。
5.1 初始化阶段的高频报错
初始化时报错,是安装阶段最让人头疼的事。我遇到的第一类错误是“The designated data directory /data/mysql is not usable because the directory already exists and is not empty”。这个问题说白了就是数据目录里有文件。我的经验是初始化前,确认数据目录必须是一个全新的空目录。即使目录里只有一个无关文件,MySQL 也会拒绝初始化。
第二类错误是缺少依赖库导致的,报错形式五花八门。典型的是:
./mysqld: error while loading shared libraries: libnuma.so.1: cannot open shared object file解决方法是提前安装 numactl 和 libaio。这个坑我印象太深了,初始化脚本检查依赖不到位,报错信息又不够直白,如果你没有相关知识,很难想到只是缺了个系统包。
第三类是配置文件权限或目录属主不对。MySQL 8.0 要求配置文件和数据目录都必须能被 mysql 用户读取和写入。我在调试过程中,因为 /data/mysql 属主忘记改成 mysql,启动时日志里反复报权限拒绝。这种事看似低级,但越忙越容易漏掉。
5.2 运行阶段的内存管理问题
运行中最常见的现象是:MySQL 占用内存随着时间不断缓慢增长,甚至不重启就持续攀升。这通常不是严格意义上的内存泄漏,而是 Performance Schema 开启了、连接缓冲反复分配等积累导致。我先确认 performance_schema 已关闭,再监控连接数变化,排除连接泄漏,内存就会稳定下来。
有一种情况需要特别警惕:如果 free -h 显示 Swap 使用量持续升高且不回落,说明物理内存确实不够用了。这时先别急着调大各种 buffer,先看看到底是什么查询在吃内存。用 performance_schema 的 events_statements_summary_by_digest 统计最耗内存的语句。但这里有个悖论——开启 performance_schema 本身就会增加内存开销。所以在小内存机器上,我会定期开一次,抓到明显异常的 SQL 后立刻关闭。
另一个常见问题是 max_connections 设置过小导致的应用报错“Too many connections”。这时不要简单粗暴地把 max_connections 拉到 500,因为每个连接都要吃内存。正确做法是确认应用是否真的需要这么多并发,让应用侧做连接池,限制空闲连接,再按实际需求设置 max_connections。
5.3 内存状态监控的实用命令集
排障离不开监控工具,这里分享几个在 2G 内存机器上特别常用的命令组合。
进程层面是最基础的检查,用 ps 查看 mysqld 的驻留内存,并观察整机内存用量:
ps aux | grep mysqld free -h更细的维度用 pidstat,查看 mysqld 的缺页次数。如果缺页次数频繁,说明内存缓存可能不足,数据页在不断被淘汰和重新读取:
pidstat -r -p $(pidof mysqld) 1如果怀疑有 SQL 查询占大量内存,可以通过 slow log 抓长语句,或短时间开启 performance_schema 后通过 information_schema 查看语句统计。但注意,用完后一定要确认关闭:
SELECT SCHEMA_NAME, DIGEST_TEXT, COUNT_STAR, SUM_ROWS_EXAMINED, SUM_ROWS_SENT FROM performance_schema.events_statements_summary_by_digest ORDER BY SUM_ROWS_EXAMINED DESC LIMIT 10;我自己的习惯是设置一个定时任务,每小时记录一次内存和 Swap 用量,保留历史数据。这样出现问题后可以对照时间线排查——比如内存是不是在某个时间段突然飙升,Swap 是不是和某个定时任务有关。排查效率会高很多。
6. 运行期经验总结:几个“非典型但极重要”的细节
前面把安装配置流程完整跑了一遍,最后再集中讲几个运行期摸索出来的细节。这些东西单拿出来都不起眼,但合在一起,决定了整台机器能不能长期稳定。
第一个细节是日志策略。MySQL 8.0 的 error log 如果长期不管,会在查询异常时疯狂增长占满磁盘。尤其慢查询日志,如果某个 SQL 出现全表扫描,慢日志文件可能几天内就从几十 MB 涨到几个 G。我设置了 log_error 和 slow_query_log 之后,还会定期用 logrotate 或定时任务清理日志文件。但要注意——不要直接用 rm 删除正在被 MySQL 写入的日志文件,否则文件句柄依然被占用,磁盘空间不会释放。正确做法是 truncate 或重命名后重建一个同名文件。
第二个是网络连接层面的隐患。MySQL 8.0 默认监听 IPv6/IPv4 回环地址,在云服务器上,如果没做好防火墙限制,3306 端口对外网开放是攻击者最喜欢的目标。我建议 bind-address 设置为内网 IP 或 127.0.0.1,并用 skip_name_resolve 减少 DNS 反查开销。对于只需要本机访问的场景,直接绑 127.0.0.1,这样最稳。
第三个是该说的延伸思路。MySQL 8.0 的 InnoDB 其实还提供了一个关于大内存的取舍思路——如果你的服务器磁盘是 SSD,将 innodb_flush_method 保持 O_DIRECT,同时适当降低 buffer pool,用 SSD 的快速随机读来弥补内存缓存的不足。我在实际测试中发现,2G 内存 + SSD 的组合,在简单查询场景下,性能与 4G 内存配置的差距并不像想象中那么大。但如果你的磁盘是机械硬盘,buffer_pool 就尽量不要压缩,否则磁盘 I/O 会成为严重的性能瓶颈。
最后,从实操中我的个人体会是:在 2G 内存的服务器上跑 MySQL 8.0,最大的敌人从来不是 MySQL 本身,而是默认参数假设了“你很有钱”。把内存账算清楚,把每个参数为什么会占用这么多内存都搞明白,再根据自己的业务负载去反向设定,2G 内存跑 8.0 不仅可行,而且能稳定。这套配置我已经在真实的个人业务环境用了两个多月,中间系统重启过一次,MySQL 通过 systemd 自动拉起,数据零丢失。如果你手头也只有一台 2G 内存的机器,完全可以按这篇文章的方案试一次——装好后你会和我一样发现,MySQL 8.0 并没有传说中那么“娇气”,很多时候是默认配置把人劝退了而已。