1. 在 Ubuntu 22.04 上装 MySQL,我踩过的那些坑
这年头,一说“装 MySQL”,网上一搜一大把教程,但真到自己动手的时候,尤其是 Ubuntu 22.04 这台机器上,各种稀奇古怪的问题就冒出来了。什么mysql命令找不到、root用户登不进去、字符集乱码、systemctl状态不对……我前前后后在不同机器上装过不下十次,每次都能遇到新问题。所以这次干脆把整个流程从零到一捋一遍,把我踩过的坑、绕过的弯路、最后沉淀下来的可靠做法,全写出来。
这篇内容适合谁?刚接触 Linux 的小白,照着走一遍能把 MySQL 跑起来;有一定经验但老在某些细节上卡壳的同学,可以当避坑手册查;就算你是老手,里面关于配置调优、权限模型、日志排查的“为什么”,也值得瞄一眼。我保证,里面没有一个步骤是“感觉应该这样做”,全部是我实测过、确认过、能落地的方案。
核心关键词:ubuntu22.04、mysql安装、mysql配置、root登录、字符集。后面所有内容都围着这些转。
2. 动手之前,先弄明白这版 MySQL 和 Ubuntu 的关系
2.1 从官方仓库装,还是从 Ubuntu 自带源装?
这是第一个分歧点。Ubuntu 22.04 自带 APT 源里就有mysql-server包,直接sudo apt install mysql-server就能装。但你会发现,装上的是 MySQL 8.0 的某个特定小版本,这个版本号不一定是最新的,而且 Ubuntu 团队可能会打一些自己的补丁。
我个人的建议是:如果只是本地开发、学习用,直接用 APT 装官方源里的版本完全够用,省心省力;如果是要上生产环境,想要官方最新小版本、或者要装 MySQL 8.4 LTS 这种版本,那就得用 MySQL 官方 APT 源。
怎么判断装的是哪个版本?装完后跑一句:
mysql --version我这边 APT 默认装出来的是mysql Ver 8.0.32-0ubuntu0.22.04.1 for Linux on x86_64,这个版本号看着挺长,但核心就是 8.0.32,跑业务足够了。
2.2 为什么我不用 Docker 装
现在很多教程喜欢让你用 Docker 拉镜像跑 MySQL,五分钟搞定。我也用 Docker 跑过一阵子,省事是真省事,但有几个问题:
- 数据卷挂载、权限配置、网络模式,对新手来说并不比裸装简单,反而多了好几层概念需要理解。
- 容器内文件系统分层导致 IO 性能损耗,虽然不大,但跑高并发压测的时候能感觉到。
- 调参数不方便,改个
my.cnf还要进容器或者启动时挂配置,没有宿主机改完systemctl restart来得直接。
所以我这篇还是聚焦在 Ubuntu 宿主机上原生安装的方式。这也更接近绝大多数云服务器、物理机部署的真实场景。
3. 安装前准备:系统更新和依赖检查
3.1 先更新索引,再动手
不管从哪个源装,第一步都是把软件源索引刷新一下:
sudo apt update这个命令本身不装东西,只是从/etc/apt/sources.list和/etc/apt/sources.list.d/下加载的源里拉取最新的软件包列表。我之前见过有人跳过这步直接apt install,结果装到一个很旧的版本,甚至直接装失败,因为 APT 不知道你的系统有哪些可用包。
如果更新索引时遇到Some index files failed to download之类的报错,大概率是网络问题,或者某个源的地址变了。在 22.04 上常见的是archive.ubuntu.com被墙或者慢,可以把主源换成国内镜像,比如阿里云或清华的镜像,具体做法我就不展开了,搜索“Ubuntu 22.04 更换国内源”就有。
3.2 确认系统里没有冲突的遗留包
这一步很容易忽略。如果之前装过 MariaDB 或者其他版本乱七八糟的 MySQL,直接装mysql-server可能会起冲突,报dpkg: error processing package ...这种错。
稳妥的操作是先查一下:
dpkg -l | grep -E "mysql|mariadb"如果有输出,尤其是带ii状态标识的,说明系统里已经有相关包了。要么卸载干净,要么先看看你是不是已经装过 MySQL 了,别重复装。
卸载时注意:
sudo systemctl stop mysql sudo apt purge mysql-server mysql-client mysql-common -y sudo apt autoremove -ypurge会更彻底一些,把配置文件也删了。如果是特意保留数据,只重新装软件,就别purge,用remove就行。
3.3 检查端口占用
MySQL 默认监听 3306 端口。如果之前有别的进程占着,后面启动必然失败。检查命令:
ss -tlnp | grep 3306没有输出说明端口空闲。如果有输出,看下是谁占用的,处理掉再继续。这个问题在云服务器上尤其常见,有时候可能是别的数据库服务或者某个监控 agent 占了。
4. 正式安装:两种方式任选
4.1 方式一:APT 直接安装(推荐新手)
当更新完索引、确认没有冲突包之后,直接一条命令:
sudo apt install mysql-server -y这个命令会拉取mysql-server以及它依赖的所有包,包括mysql-client、mysql-common、libmysqlclient系列等,装完后服务通常会自动启动。
验证是否装好,可以跑:
systemctl status mysql看到active (running)就是成功了。如果没自动启动,手动启动:
sudo systemctl start mysql装完顺手看一下版本:
mysql --version4.2 方式二:MySQL 官方 APT 仓库安装
如果想装更新的版本,比如 MySQL 8.0.x 的最新小版本,或者直接上 8.4 LTS,可以用官方 APT 仓库。步骤如下:
先下载并安装 MySQL 官方的 APT 配置包:
wget https://dev.mysql.com/get/mysql-apt-config_0.8.29-1_all.deb sudo dpkg -i mysql-apt-config_0.8.29-1_all.deb装的时候会弹出对话框让你选要哪个产品、哪个版本。默认选MySQL Server 8.0就行,如果菜单里出现了 8.4 LTS 就选那个,看你自己需求。选完Ok确认,然后:
sudo apt update sudo apt install mysql-server -y注意,这里sudo apt install mysql-server装的就是官方源里的版本了,不是 Ubuntu 自带的。装完版本号会更新,比如 8.0.40 之类。
这种方式的好处是以后apt upgrade可以一直跟着官方小版本走,坏处是如果没配置好优先级,有可能会和 Ubuntu 自带的包产生冲突。不过我用下来,22.04 上加官方源挺干净的,目前没遇到过大问题。
4.3 两种方式怎么选
| 对比维度 | APT 默认源 | 官方 APT 源 |
|---|---|---|
| 安装难度 | 极低,一条命令 | 中等,多两步下载配置包 |
| 版本更新速度 | 慢,随 Ubuntu 发布节奏 | 快,官方维护 |
| 稳定性 | 高,经过 Ubuntu 测试 | 高,官方测试,但升级频繁 |
| 适用场景 | 个人开发、学习、小项目 | 生产环境、需要长期维护的项目 |
我的建议:新手第一次装,用方式一。别一开始就折腾官方源,等熟悉了或者有版本需求了再换,也不是什么难事。
5. 安装完成后的核心配置
装完不等于配完,MySQL 默认配置非常保守,不处理一下基本用不成。这个环节是最花时间的,也是最多人卡住的地方。
5.1 服务管理基础
先掌握这套服务管理命令,后面都用得上:
# 查看状态 sudo systemctl status mysql # 启动 sudo systemctl start mysql # 停止 sudo systemctl stop mysql # 重启 sudo systemctl restart mysql # 设置开机自启 sudo systemctl enable mysql注意,在 Ubuntu 上服务名是mysql,不是mysqld。在 CentOS 或者老版本 Ubuntu 上叫mysqld,别搞混了。我看过有人对着systemctl start mysqld折腾半天,结果系统里根本没有这个服务。
5.2 初始化安全配置
MySQL 8.0 装完后,默认root账号用的是auth_socket插件认证,也就是说,只有系统root用户直接通过 socket 连才能进 MySQL。这时候你跑mysql -u root -p是进不去的,因为没有密码。
正确的做法是走官方自带的初始化安全脚本:
sudo mysql_secure_installation这个脚本会跟你一连串交互问答:
VALIDATE PASSWORD COMPONENT问你要不要启用密码强度校验插件。我建议本地开发场景选 No,生产环境选 Yes。密码强度校验会强制要求密码包含大小写、数字、特殊字符,而且长度至少 8 位。如果你是新手或者本地玩,很容易被这套规则搞烦,先关掉。Remove anonymous users?问要不要删匿名用户,选Y,必须删。Disallow root login remotely?问要不要禁止 root 远程登录,选Y,默认就该禁止。Remove test database and access to it?问要不要删测试库,选Y,不用留。Reload privilege tables now?问要不要重载权限表,选Y,让改动生效。
全程选 Y 就行,除了密码强度校验那里可以看情况选。
脚本跑完,MySQL 的初始安全加固就差不多了。注意,如果脚本报错说 root 密码已经存在之类,说明你之前手欠已经改过密码,不影响,直接往下走。
5.3 密码和认证方式相关的那些坑
这是整个安装配置过程中最常见的困局。我见过太多人卡在“明明密码是对的,却登不进去”。
在 MySQL 8.0 里,默认的caching_sha2_password认证插件对老客户端不友好,比如 PHP 7.1 以下、Python 的旧版 MySQLdb 等。如果你连的是本地回环,还好说;一旦涉及远程连接或者其他语言的驱动,可能就报这个错:
Access denied for user 'root'@'localhost'或者你的客户端提示:
Authentication plugin 'caching_sha2_password' cannot be loaded解决办法有两个方向:
方向一:不要用 root 远程连,新建一个普通账户,专门给应用用:
CREATE USER 'appuser'@'%' IDENTIFIED BY 'StrongPass@123'; GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'%'; FLUSH PRIVILEGES;方向二:如果你心里有执念,非要用 root 远程连,那就给 root 换个认证插件:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码';注意,mysql_native_password在 8.0 里属于过时不推荐使用的插件,MySQL 官方说在后续版本中可能移除,新项目不建议用。作为从业者,我更推荐方向一,为每个应用建独立账号,权限最小化,这是规矩。
5.4 改绑定地址,允许远程连接
MySQL 默认只监听127.0.0.1,也就是说只有本机可以连,其他机器想连你这个数据库会被拒绝。这在开发机上是好事,安全性高;但你要是想把数据库跑在服务器上给别的应用连,就得改配置。
改配置文件:
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf找到这一行:
bind-address = 127.0.0.1改成:
bind-address = 0.0.0.0或者注释掉这行(默认监听所有地址)。改完重启服务:
sudo systemctl restart mysql改完后远程连接时,还要保证你建的数据库用户允许从任意主机连接('root'@'%'或者'appuser'@'%'),否则就算监听开了,权限表也会拦截。
这里面有一个安全悖论:改成0.0.0.0意味着所有网卡都暴露了,如果服务器上有公网 IP,就等于数据库裸奔在了公网上。我强烈建议:云服务器上如果要监听公网,先配防火墙白名单,只允许特定 IP 访问 3306 端口,而不是图省事全放开。
5.5 字符集设置
很多项目在导入数据或者写入中文时出现?乱码,几乎都和字符集设置有关。MySQL 8.0 默认用的是utf8mb4,比老旧的utf8更全面,能存 emoji、生僻字等。如果你不确定当前字符集是什么,进 MySQL 看一下:
SHOW VARIABLES LIKE 'character_set_%';正常情况下应该是:
character_set_server utf8mb4 character_set_database utf8mb4如果发现不是,在配置文件里显式指定:
[mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci改完重启sudo systemctl restart mysql。注意,已经建好的库和表,字符集不会自动变,需要手动改:
ALTER DATABASE 库名 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ALTER TABLE 表名 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;为了这点,我提醒过不少同事,项目一开始建库建表的时候就确认好字符集,别等到线上跑了一堆数据再改,那是给运维上眼药。
5.6 时区设置
这个问题看起来不起眼,真遇上了特别烦。如果你的应用是面向国内用户的,MySQL 默认的时区是系统时区(通常跟随 Ubuntu 设置),但如果你的 Ubuntu 时区是 UTC,那存进去的TIMESTAMP类型字段会差 8 个小时。
查看时区:
SHOW VARIABLES LIKE 'time_zone';如果是+00:00或者SYSTEM但系统是 UTC,就要处理。改配置文件增加:
[mysqld] default-time-zone = '+08:00'或者用 SQL 设:
SET GLOBAL time_zone = '+08:00';注意,SET GLOBAL只对当前运行实例生效,重启就丢了,所以最终还是要写进配置文件。
6. 数据目录与日志:搞清楚它们在哪里,出事才不慌
6.1 数据目录和配置文件位置速查
| 路径 | 作用 |
|---|---|
/etc/mysql/ | 配置文件目录,主文件是my.cnf |
/etc/mysql/mysql.conf.d/mysqld.cnf | Ubuntu 下 mysqld 的主要配置段所在 |
/var/lib/mysql | 数据库数据文件的默认存放目录 |
/var/log/mysql/error.log | MySQL 错误日志 |
/var/run/mysqld/ | 进程运行时目录,包含 socket 文件 |
/etc/mysql/debian.cnf | Debian/Ubuntu 特有的维护账号配置文件 |
debian.cnf这个东西是很多新手的盲区。它里面存了 Debian 系系统维护 MySQL 用的账号和密码(类似debian-sys-maint),日常我们基本用不到,但是系统脚本维护、自动备份之类可能会用到它。不需要特意去改,知道有这个东西存在就行。
6.2 日志怎么看
排查问题第一件事就是看日志,别瞎猜。看 MySQL 错误日志:
sudo tail -f /var/log/mysql/error.log常见启动失败场景,比如权限问题、my.cnf写错、磁盘满了,都能在错误日志里找到蛛丝马迹。比如:
[ERROR] [MY-010584] InnoDB: Operating system error number 13 in a file operation.意思是文件权限不对,多半是/var/lib/mysql目录的属主不对或者 SELinux/AppArmor 拦截了。
Ubuntu 默认开启了 AppArmor 对 MySQL 的保护,如果改了数据目录到自定义路径,比如/data/mysql,AppArmor 可能会拦截访问,启动会报错。解决办法是把新路径配置进 AppArmor 的规则里,或者临时禁用它。我建议别随意改数据目录,除非你很清楚自己在做什么。
6.3 数据备份的意识要早点有
谈了这么多配置,插一句备份。装完 MySQL 之后第一件事,我建议先验证一下备份和恢复的流程能不能走通,别等到数据没了再后悔。
最简单的逻辑备份工具是mysqldump:
mysqldump -u root -p 库名 > 库名.sql恢复:
mysql -u root -p 库名 < 库名.sql生产环境可以配cron定时备份,也推荐用xtrabackup做物理备份。这些展开讲又是一篇,这里提一句:工具用顺手,灾难少一半。
7. 新建数据库和用户:日常操作的正确姿势
7.1 建库建用户的规范流程
进入 MySQL 客户端:
sudo mysql注意,这里不需要密码,因为前面提到过,通过系统 root 用户走 socket 直接用auth_socket认证。输入命令:
CREATE DATABASE testdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'password123'; GRANT ALL PRIVILEGES ON testdb.* TO 'testuser'@'localhost'; FLUSH PRIVILEGES;这样就建好了一个库和一个只能从本机连的用户。如果要允许远程连,把'localhost'换成'%':
CREATE USER 'testuser'@'%' IDENTIFIED BY 'password123'; GRANT ALL PRIVILEGES ON testdb.* TO 'testuser'@'%'; FLUSH PRIVILEGES;注意,这里%是通配符,代表任意主机,安全上要慎重,还是那句话,配合防火墙用。
7.2 GRANT 和 FLUSH PRIVILEGES 的关系
很多旧教程在GRANT后面都要加一句FLUSH PRIVILEGES。实际上在 8.0 里,GRANT语句执行后权限是立即生效的,FLUSH PRIVILEGES主要用处是重新读取授权表,通常在你直接修改了mysql.user表(例如用UPDATE改密码)之后才需要。规范的做法是用GRANT/ALTER USER而不是手动改表,这样根本不需要FLUSH。但多写一句也不会有副作用,习惯无害。
7.3 权限最小化原则
我给项目分配账号时,从来不会直接给ALL PRIVILEGES ON *.*。而是用得着哪个库,就给哪个库的权限;需要读写,就给SELECT, INSERT, UPDATE, DELETE;只要读,就给SELECT。这样一旦账号泄露,损失半径能控制在最小。
查看一个用户的权限:
SHOW GRANTS FOR 'testuser'@'localhost';撤销权限:
REVOKE DELETE ON testdb.* FROM 'testuser'@'localhost';多用户管理是生产环境的基本功,别怕麻烦。
8. 实际踩坑记录:三个最有代表性的问题
8.1 问题一:系统 root 用户都进不去 MySQL
现象:
sudo mysql ERROR 1045 (28000): Access denied for user 'root'@'localhost'原因:MySQL 8.0 的 root 账号如果是用auth_socket插件,正常情况下系统 root 通过 socket 连接是能进去的。如果报这个错,大概率是之前有人把 root 的认证方式改成了密码认证。
解决:修改配置文件,临时跳过权限验证启动:
sudo systemctl stop mysql sudo mkdir -p /var/run/mysqld sudo chown mysql:mysql /var/run/mysqld # 以跳过权限表方式启动 sudo mysqld --skip-grant-tables &然后另开一个终端:
sudo mysql进入后用 SQL 把 root 认证改回 socket 或重新设密码:
FLUSH PRIVILEGES; ALTER USER 'root'@'localhost' IDENTIFIED WITH auth_socket;如果要用密码登录,就:
ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY '新密码';改完退出,把刚才后台启动的 mysqld 杀掉:
sudo killall mysqld sudo systemctl start mysql注意--skip-grant-tables模式下 MySQL 是不带权限校验的,安全风险极大,只能本机临时使用,用完立刻恢复。这算是压箱底的救援手段了。
8.2 问题二:报错Fatal error: Please read "Security" section of the manual to find out how to run mysqld as root!
这个报错一般出现在直接用mysqld启动而不是用systemctl启动,而且你是用 root 用户去跑的时候。因为 MySQL 默认不允许直接用 root 系统用户运行 mysqld 进程,防止安全风险。
解决:用mysql用户来运行:
sudo -u mysql mysqld或者干脆不要手动跑,都用systemctl管理。
8.3 问题三:mysql 进程占用 CPU 很高
现象:装完没跑任何业务,top一看 mysqld 占 CPU 50% 以上。
原因分析:刚初始化完 MySQL,要做buffer pool预分配、各种统计信息重建,短期内 CPU 高正常。也有可能是 InnoDB 的innodb_buffer_pool_size设置得太大,内存不够就开始疯狂交换。
排查:
sudo mysql -e "SHOW ENGINE INNODB STATUS\G;"主要看有没有大量的查询在跑,以及内存相关的指标。如果是空闲但 CPU 高,可以试试降低innodb_buffer_pool_size,比如:
[mysqld] innodb_buffer_pool_size = 256M重启生效。开发机设 128M-256M 足够了,别照着网上大 V 的生产配置抄,动不动 16G 起步,会把你的小内存机器直接搞趴。
9. 基于实际应用的配置优化建议
9.1 内存配置,量力而行
innodb_buffer_pool_size是 MySQL 最大的内存消费者,它是 InnoDB 存储引擎的缓存池,用来缓存表数据和索引。常见的经验值是物理内存的 60%-70%,但开发机压根不用这么大。举个例子,一台 2G 内存的轻量云主机,你把 pool 设成 1.5G,系统内存就炸了,OOM Killer 分分钟把 mysqld 杀掉。
可以先看当前值:
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';我的建议:
| 物理内存 | 建议 buffer pool |
|---|---|
| 2G | 256M-512M |
| 4G | 512M-1G |
| 8G | 2G-4G |
| 16G+ | 8G-10G |
配置文件写好后留意max_connections,默认 151 挺保守的,并发高就适当调高,但别一下子涨到 2000,每个连接都要内存的,小马拉大车必出事。
9.2 慢查询日志,新手也该开
慢查询日志是定位 SQL 性能问题的第一利器。默认关闭,就是怕没人看日志白耗磁盘。我建议开发机也开一下,养成习惯:
[mysqld] slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log long_query_time = 2long_query_time表示超过几秒的 SQL 会被记录,开发阶段设 2 秒就可以。然后定期看一眼:
sudo tail -f /var/log/mysql/slow.log工作中因为没看慢查询导致线上事故的案例太多了,早养成习惯少背锅。
9.3 二进制日志开启与用途
binlog对于基于时间点的恢复、主从复制非常关键。MySQL 8.0 默认是开启的,可以在配置里调整格式:
[mysqld] server-id = 1 log-bin = mysql-bin binlog_format = ROWROW格式记录每一行数据的变更,对数据一致性最友好,虽然日志量会大一些。开发机不开也行,但建议至少知道它在配置文件里长什么样。
9.4 防火墙配置(关键一步)
如果你在云服务器上开通了 MySQL 远程访问,一定记得同步配置防火墙。Ubuntu 上一般用ufw:
sudo ufw allow from 你的IP地址 to any port 3306 sudo ufw enable如果没有特定 IP,只允许内网网段:
sudo ufw allow from 10.0.0.0/8 to any port 3306不要用sudo ufw allow 3306这种把 3306 暴露给全世界的方式。安全上的投入,永远比性能优化性价比更高。
10. 从装完到能跑业务:一份完整流程清单
光说不练假把式,我把从零到能跑业务的最小流程给你列出来,每一步都验证过:
- 系统更新:
sudo apt update - 安装:
sudo apt install mysql-server -y - 确认启动:
systemctl status mysql - 安全初始化:
sudo mysql_secure_installation - 进 MySQL:
sudo mysql - 建库:
CREATE DATABASE app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 建用户并授权:
CREATE USER 'app'@'localhost' IDENTIFIED BY '你的密码'; GRANT ALL PRIVILEGES ON app.* TO 'app'@'localhost'; - 退出测试:
exit mysql -u app -p能进就说明装好了,后面再根据项目需求去调整字符集、时区、远程访问、内存参数等。
这段流程跑完,你的 Ubuntu 22.04 上就是一个能正常开机自启、能建库建用户、能跑业务代码的 MySQL 环境了。后面再遇到问题,大多是应用层的连接参数、SQL 写法或者权限配置问题,基本和“安装配置”没太大关系了。
11. 最后再分享几个小技巧
按说博文到这也差不多该结束了,但还有几个散装经验,我在多次装机会中总结出来的,放结尾分享给你。
第一个技巧,装完先别急着改配置。默认配置实际上对多数小项目来说完全够用,真正的瓶颈往往在 SQL 本身,而不是 MySQL 服务器参数。我看到太多人连一条索引都没建过,天天琢磨innodb_buffer_pool_size,方向完全错了。
第二个技巧,命令行记不住参数就写一个小脚本。比如建库建用户这种重复操作,我通常会写一个 SQL 文件模板,改成库名用户名密码一次执行:
CREATE DATABASE `:库名` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER ':用户名'@'localhost' IDENTIFIED BY ':密码'; GRANT ALL PRIVILEGES ON `:库名`.* TO ':用户名'@'localhost'; FLUSH PRIVILEGES;手动执行时替换掉冒号占位符就行,比每一次手敲强得多。
第三个技巧,定期看日志,别等出问题再看。我给自己的习惯是每次重启服务之后都顺手看一眼错误日志,确认没有新的报错;服务器上的定时任务也加上了简化版的慢查询日报。这个习惯救了我不止一次,因为很多隐患在日志里早就露出苗头了。
最后一个是心态上的。装 MySQL 不算难,真正难的是遇到问题时不慌,按日志找线索,按权限、端口、配置、SQL 这个顺序逐个排查。你照着这篇装一次、跑一次、主动改几次配置,比看十篇教程都有用。真遇到本文没覆盖到的报错,带着错误日志和配置上下文去搜,基本都能解决。