MySQL安装教程:图文教程从零开始,手把手教你搭建稳定高效的数据库环境
对于开发者、运维人员乃至刚入门的IT从业者来说,MySQL几乎是绕不开的第一关。无论是搭建个人博客、企业官网,还是开发复杂的业务系统,MySQL作为全球最流行的开源关系型数据库,凭借其稳定、高效、免费的特性,始终是后端存储方案的首选。
本文将以CentOS 7系统为例,采用MySQL二进制安装方式,从环境检查、版本选择,到安装执行、安全初始化、远程访问开启、启动报错的排查,每一步都配有完整命令和注释。读完这篇教程,你不仅能顺利装好MySQL,更将理解每个配置背后的逻辑,真正做到“装得对、用得好、排得了错”。
适用人群:运维工程师、后端开发、云服务器使用者、Linux初学者
前置要求:一台CentOS 7服务器,如果还没有,可以参考我前面的文章,VMware安装centos教程:https://www.cnblogs.com/dbbull/p/20891421
一、Linux安装MySQL规范
1.1 MySQL安装方式
- 推荐方式:二进制安装(
tar包解压即用) - 其他方式:源码编译、Yum、RPM(不展开)
1.2 MySQL 运行用户
- 使用虚拟用户
mysql:mysql,仅用于进程运行,禁止登录、不创建家目录 - 创建命令:
useradd -s /sbin/nologin -M mysql
1.3 MySQL目录规范
| 用途 | 路径示例 |
|---|---|
| 下载目录 | /server/tools |
| 系统目录 | /opt/mysql/mysql-8.0.45 |
| 软链接 | ln -s /opt/mysql/mysql-8.0.45 /usr/local/mysql |
| 数据目录 | /data/mysql/mysql3306/{data,logs} |
| 配置文件 | /data/mysql/mysql3306/my3306.cnf |
1.4 MySQL安装依赖环境检查
- GNU libc 版本 必须 ≥ 2.17(否则启动报错)
- 查看命令:
ldd --version
示例输出:
ldd (GNU libc) 2.17
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
由 Roland McGrath 和 Ulrich Drepper 编写。
二、Linux安装 MySQL 8.0(完整步骤)
下载MySQL8.0安装包(不要选择过低的版本,后面的版本会修复已知的bug,过低的版本bug较多,谨慎选择):
通过网盘分享的文件:mysql-8.0.45-linux-glibc2.17-x86_64
链接: https://pan.baidu.com/s/1DBY3D1h2Up4z-jMemxNSuA?pwd=5xib 提取码: 5xib
--来自百度网盘的分享
2.1 准备工作
# 1. 创建虚拟用户
useradd -s /sbin/nologin -M mysql

# 2. 创建所需目录
mkdir -p /server/tools
mkdir -p /opt/mysql
mkdir -p /data/mysql/mysql3306/{data,logs}

# 3. 进入下载目录
cd /server/tools
# 4. 上传二进制包(若没有 lrzsz,先 yum install -y lrzsz)
rz

💡 课堂小技巧
- 快速备份:
cp a.txt{,.bak}- 删除文件前先用
mv移到/tmp,确认无用后再删除,避免误删。
2.2 解压与移动
# 解压(包名以实际为准)
tar xf mysql-8.0.45-linux-glibc2.17-x86_64.tar.xz

# 移动到规范目录
mv mysql-8.0.45-linux-glibc2.17-x86_64 /opt/mysql/mysql-8.0.45

# 创建软链接
ln -s /opt/mysql/mysql-8.0.45 /usr/local/mysql

2.3 移除系统自带 MariaDB(避免冲突)
rpm -e --nodeps mariadb-libs

2.4 编辑配置文件
vim /data/mysql/mysql3306/my3306.cnf
配置内容(参考):
[mysqld]
user=mysql
basedir=/usr/local/mysql
datadir=/data/mysql/mysql3306/data
socket=/data/mysql/mysql3306/mysql.sock
server_id=1
port=3306
log_error=/data/mysql/mysql3306/logs/error.log
log_bin=/data/mysql/mysql3306/logs/mysql-bin
binlog_format=row
gtid_mode=on
enforce_gtid_consistency=true
log_slave_updates=1
max_connections=1024
wait_timeout=60
sort_buffer_size=2M
max_allowed_packet=32M
join_buffer_size=2M
innodb_buffer_pool_size=128M
innodb_flush_log_at_trx_commit=1
innodb_log_buffer_size=32M
innodb_log_file_size=128M
innodb_log_files_in_group=2
binlog_cache_size=2M
max_binlog_cache_size=8M
max_binlog_size=512M
expire_logs_days=7
slow_query_log=on
slow_query_log_file=/data/mysql/mysql3306/logs/slow.log
long_query_time=0.5
log_queries_not_using_indexes=1

2.5 安装依赖包
yum install libaio-devel numactl -y

2.6 更改目录权限
chown -R mysql:mysql /data/*

2.7 初始化数据库(空密码)
/usr/local/mysql/bin/mysqld \
--defaults-file=/data/mysql/mysql3306/my3306.cnf \
--initialize-insecure \
--user=mysql \
--basedir=/usr/local/mysql \
--datadir=/data/mysql/mysql3306/data
✅
--initialize-insecure表示 root 密码为空;若用--initialize则生成随机密码并记录在 error.log。

2.8 配置环境变量
echo 'PATH="/usr/local/mysql/bin:$PATH"' >> /etc/profile
source /etc/profile

2.9 启动 MySQL
mysqld --defaults-file=/data/mysql/mysql3306/my3306.cnf &
2.10 验证启动
netstat -lntup | grep mysql

三、连接 MySQL 的方式
- 本地连接(使用 socket):
无需输入密码,回车即可连接 mysql -uroot -p -S /data/mysql/mysql3306/mysql.sock

- 远程连接(TCP/IP):
默认没有远程连接的用户,需要单独创建 mysql> create user root@'%' identified by '123456'; Query OK, 0 rows affected (0.04 sec) mysql> grant all on *.* to root@'%'; Query OK, 0 rows affected (0.01 sec) mysql> mysql -uroot -p -P3306 -h192.168.80.80

四、常用sql语句
4.1. 数据库操作
-- 创建数据库(指定字符集)
CREATE DATABASE IF NOT EXISTS mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 查看所有数据库
SHOW DATABASES;
-- 切换/使用数据库
USE mydb;
-- 查看当前所在数据库
SELECT DATABASE();
-- 删除数据库(谨慎操作)
DROP DATABASE IF EXISTS mydb;
4.2. 建表语句(含各类约束)
-- 标准建表(主键、自增、默认值、注释、唯一约束、外键)
CREATE TABLE IF NOT EXISTS `users` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户ID(主键)',
`username` VARCHAR(50) NOT NULL COMMENT '用户名',
`email` VARCHAR(100) NOT NULL COMMENT '邮箱',
`phone` VARCHAR(20) DEFAULT NULL COMMENT '手机号',
`password_hash` VARCHAR(255) NOT NULL COMMENT '密码哈希',
`age` TINYINT(3) UNSIGNED DEFAULT 0 COMMENT '年龄',
`salary` DECIMAL(10,2) DEFAULT 0.00 COMMENT '月薪',
`status` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`), -- 唯一索引
UNIQUE KEY `uk_email` (`email`),
KEY `idx_status_created` (`status`, `created_at`) -- 联合普通索引
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表';
-- 创建关联表(带外键)
CREATE TABLE `orders` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INT(11) UNSIGNED NOT NULL COMMENT '关联用户ID',
`amount` DECIMAL(10,2) NOT NULL,
`order_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
CONSTRAINT `fk_orders_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
4.3. 表结构修改(ALTER TABLE)
-- 添加列
ALTER TABLE users ADD COLUMN `address` VARCHAR(200) DEFAULT NULL COMMENT '地址';
-- 修改列类型/属性
ALTER TABLE users MODIFY COLUMN `phone` VARCHAR(30) NOT NULL COMMENT '手机号';
-- 修改列名(同时改类型)
ALTER TABLE users CHANGE `phone` `mobile` VARCHAR(20) NOT NULL COMMENT '手机号';
-- 删除列
ALTER TABLE users DROP COLUMN `address`;
-- 添加索引
ALTER TABLE users ADD INDEX idx_age (`age`);
ALTER TABLE users ADD UNIQUE INDEX uk_phone (`mobile`);
-- 删除索引
ALTER TABLE users DROP INDEX idx_age;
-- 重命名表
RENAME TABLE users TO user_info;
-- 或
ALTER TABLE user_info RENAME TO users;
-- 查看表结构
DESC users;
-- 或查看建表语句
SHOW CREATE TABLE users;
4.4. 清空表(两种方式区别大)
-- 方式1:删除所有数据,保留表结构,自增计数器归零,可回滚(事务内)
DELETE FROM users;
-- 方式2:清空表,自增计数器归零,速度极快,不可回滚(DDL操作)
TRUNCATE TABLE users;
4.5. INSERT(插入)
-- 标准插入(指定列)
INSERT INTO users (username, email, password_hash, age, salary)
VALUES ('zhangsan', 'zhangsan@example.com', 'hash123', 28, 8500.00);
-- 批量插入(推荐,效率高)
INSERT INTO users (username, email, password_hash, age) VALUES
('lisi', 'lisi@example.com', 'hash456', 32),
('wangwu', 'wangwu@example.com', 'hash789', 25);
-- 插入时遇到重复键则更新(ON DUPLICATE KEY UPDATE)
INSERT INTO users (username, email, password_hash, age)
VALUES ('zhangsan', 'newemail@example.com', 'newhash', 29)
ON DUPLICATE KEY UPDATE
email = VALUES(email),
age = VALUES(age);
-- 插入时忽略重复键(不报错)
INSERT IGNORE INTO users (username, email, password_hash)
VALUES ('zhangsan', 'dup@example.com', 'xxx');
4.6. UPDATE(更新)
-- 更新单条(务必带WHERE,否则全表更新!)
UPDATE users SET age = 30, salary = 9000.00 WHERE username = 'zhangsan';
-- 条件更新(CASE WHEN)
UPDATE users
SET salary = CASE
WHEN age < 25 THEN salary * 1.2
WHEN age BETWEEN 25 AND 35 THEN salary * 1.1
ELSE salary * 1.05
END;
-- 联表更新(用JOIN)
UPDATE users u
JOIN orders o ON u.id = o.user_id
SET u.status = 0
WHERE o.amount < 10.00;
4.7. DELETE(删除)
-- 删除指定条件数据
DELETE FROM users WHERE age > 60 AND status = 0;
-- 联表删除(删除无订单的用户)
DELETE u FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL;
-- 安全删除:先查询确认再删除(善用事务)
START TRANSACTION;
SELECT * FROM users WHERE age > 60; -- 先看看要删哪些
DELETE FROM users WHERE age > 60;
-- 确认无误后 COMMIT; 有问题则 ROLLBACK;
4.8. 基础查询
-- 查询所有列(生产环境不推荐 *)
SELECT * FROM users;
-- 查询指定列 + 别名
SELECT id, username AS 用户名, email AS 邮箱 FROM users;
-- 去重查询
SELECT DISTINCT status FROM users;
-- 条件查询(WHERE)
SELECT * FROM users
WHERE age >= 18 AND age <= 30 AND status = 1;
-- IN / NOT IN
SELECT * FROM users WHERE id IN (1, 3, 5, 7);
SELECT * FROM users WHERE status NOT IN (0, 2);
-- BETWEEN
SELECT * FROM users WHERE age BETWEEN 20 AND 35;
-- LIKE 模糊查询(%任意字符,_单个字符)
SELECT * FROM users WHERE username LIKE '张%'; -- 以"张"开头
SELECT * FROM users WHERE email LIKE '%@qq.com'; -- QQ邮箱
-- NULL 值判断(不能用 = NULL)
SELECT * FROM users WHERE phone IS NULL;
SELECT * FROM users WHERE phone IS NOT NULL;
4.9. 排序、分页
-- ORDER BY(升序ASC默认,降序DESC)
SELECT * FROM users WHERE status = 1
ORDER BY age DESC, created_at ASC;
-- 分页查询(LIMIT offset, count)
SELECT * FROM users ORDER BY id DESC LIMIT 0, 20; -- 第1页(每页20条)
SELECT * FROM users ORDER BY id DESC LIMIT 20, 20; -- 第2页
-- 优化大偏移量分页(记录上一页最后一条ID)
SELECT * FROM users WHERE id > 1000 ORDER BY id LIMIT 20;
4.10. 聚合函数 + GROUP BY + HAVING
-- 常用聚合:COUNT, SUM, AVG, MAX, MIN
SELECT
COUNT(*) AS total_users,
AVG(age) AS avg_age,
MAX(salary) AS max_salary,
MIN(salary) AS min_salary,
SUM(salary) AS total_salary
FROM users WHERE status = 1;
-- GROUP BY 分组统计
SELECT
status,
COUNT(*) AS count,
AVG(age) AS avg_age
FROM users
GROUP BY status;
-- HAVING 对分组结果过滤(区别于WHERE)
SELECT
status,
COUNT(*) AS cnt
FROM users
GROUP BY status
HAVING cnt > 10; -- 只返回人数 > 10 的状态组
4.11. 多表连接查询(JOIN)
-- INNER JOIN(取交集)
SELECT u.username, o.amount, o.order_time
FROM users u
INNER JOIN orders o ON u.id = o.user_id
WHERE o.amount > 100;
-- LEFT JOIN(左表全保留,右表无匹配则为NULL)
SELECT u.username, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username;
-- 自连接(查询同一张表的上下级关系)
SELECT
e1.username AS employee,
e2.username AS manager
FROM users e1
LEFT JOIN users e2 ON e1.manager_id = e2.id;
-- 子查询(WHERE中)
SELECT * FROM users
WHERE id IN (SELECT DISTINCT user_id FROM orders WHERE amount > 500);
-- 子查询(FROM中,即派生表)
SELECT t.username, t.avg_amount
FROM (
SELECT u.id, u.username, AVG(o.amount) AS avg_amount
FROM users u
JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username
) t
WHERE t.avg_amount > 1000;
4.12. 高级查询技巧
-- CASE WHEN 条件判断(类似 if-else)
SELECT
username,
age,
CASE
WHEN age < 18 THEN '未成年'
WHEN age BETWEEN 18 AND 60 THEN '成年'
ELSE '老年'
END AS age_group
FROM users;
-- 窗口函数(MySQL 8.0+,排名、累计等)
SELECT
username,
salary,
RANK() OVER (ORDER BY salary DESC) AS rank_salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank,
ROW_NUMBER() OVER (PARTITION BY status ORDER BY salary DESC) AS rn
FROM users;
-- 日期函数常用
SELECT
NOW() AS 当前时间,
CURDATE() AS 当前日期,
DATE_ADD(NOW(), INTERVAL 7 DAY) AS 一周后,
DATEDIFF('2026-07-06', '2026-07-01') AS 相差天数,
DATE_FORMAT(created_at, '%Y年%m月%d日 %H:%i:%s') AS 格式化时间
FROM users LIMIT 1;
4.13. 常用运维管理命令
-- 查看所有正在运行的连接/进程
SHOW PROCESSLIST;
-- 查完整版(包含SQL语句全文)
SHOW FULL PROCESSLIST;
-- 杀掉某个连接(线程ID)
KILL 12345;
-- 查看当前数据库所有表
SHOW TABLES;
-- 查看表状态(大小、行数等)
SHOW TABLE STATUS LIKE 'users'\G
-- 查看数据文件大小(MB)
SELECT
table_schema AS '数据库',
table_name AS '表名',
ROUND(((data_length + index_length) / 1024 / 1024), 2) AS '大小(MB)'
FROM information_schema.TABLES
WHERE table_schema = 'mydb'
ORDER BY (data_length + index_length) DESC;
-- 查看当前数据库连接数相关
SHOW VARIABLES LIKE 'max_connections'; -- 最大连接数设置
SHOW STATUS LIKE 'Threads_connected'; -- 当前连接数
SHOW STATUS LIKE 'Max_used_connections'; -- 历史最高连接数
-- 查看SQL执行状态(实时监控)
SHOW ENGINE INNODB STATUS\G -- InnoDB引擎状态
4.14. 实用组合场景示例
-- 场景1:查询最近7天注册、且有过至少1笔订单的用户
SELECT DISTINCT u.id, u.username, u.created_at
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
AND o.order_time >= DATE_SUB(NOW(), INTERVAL 7 DAY);
-- 场景2:统计每个用户的订单总额,并按总额排序
SELECT
u.id,
u.username,
IFNULL(SUM(o.amount), 0) AS total_spent,
COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username
ORDER BY total_spent DESC;
-- 场景3:找出重复的邮箱
SELECT email, COUNT(*) AS cnt
FROM users
GROUP BY email
HAVING cnt > 1;
-- 场景4:插入数据,如果存在则忽略,如果不存在则插入(利用唯一键)
INSERT IGNORE INTO users (username, email, password_hash)
VALUES ('newuser', 'new@example.com', 'hashxxx');
五、常见启动失败案例与排错
🔴 案例1:目录权限不足
错误日志:
[ERROR] Could not open file '/data/mysql/mysql3306/logs/error.log' for error logging: Permission denied
原因:/data/* 属主不是 mysql:mysql
解决:
chown -R mysql:mysql /data/*
🔴 案例2:配置文件参数错误
错误日志:
[ERROR] unknown variable 'basedi=/usr/local/mysql'(拼写错误)
原因:参数名写错或版本不支持
解决:检查配置文件,修正参数名(如 basedir)。
🔴 案例3:未指定正确配置文件
现象:启动时未使用 --defaults-file,或路径错误
排查:
mysqld --verbose --help | grep defaults
解决:启动时务必带上 --defaults-file=/data/mysql/mysql3306/my3306.cnf。
🔴 案例4:端口被占用
错误日志:
[ERROR] Do you already have another mysqld server running on port: 3306 ?
原因:多实例端口冲突
解决:修改配置文件中的 port,或停止占用端口的进程。
🔴 案例5:误删二进制日志文件
错误日志:
[ERROR] Failed to open log (file '/data/mysql/mysql3306/logs/mysql-bin.000014', errno 2)
解决:编辑 mysql-bin.index,删除对应行记录。
🔴 案例6:共享表空间大小不匹配
错误日志:
[ERROR] InnoDB: The Auto-extending innodb_system data file './ibdata1' is of a different size ...
原因:innodb_data_file_path 参数与现有 ibdata1 文件大小不一致
解决:
- 若在初始化前,修改参数为默认值(≤12M)
- 若已初始化,需重新初始化(注意备份数据)。
六、启动失败通用排查方法
- 确认 MySQL 版本、启动方式及配置文件路径
- 查看错误日志(默认
error.log路径在配置中指定)tail -100 /data/mysql/mysql3306/logs/error.log
七、数据库用户安全策略
7.1 初始化方式对比
| 选项 | root 密码 | 密码存储位置 |
|---|---|---|
--initialize-insecure |
空(无密码) | 无需记录 |
--initialize |
随机生成 | error.log |
7.2 修改 root 密码
-- 方法1:ALTER USER
ALTER USER root@'localhost' IDENTIFIED BY '123456';
-- 方法2:mysqladmin(命令行)
mysqladmin -uroot -p123456 password '123' -S /data/mysql/mysql3306/mysql.sock
7.3 清理无用用户
DELETE FROM mysql.user WHERE user != 'root';
FLUSH PRIVILEGES;
7.4 创建管理用户(示例)
-- 创建用户
CREATE USER ergou@'localhost' IDENTIFIED BY '123456';
-- 授予全部权限并允许转授权
GRANT ALL PRIVILEGES ON *.* TO ergou@'localhost' WITH GRANT OPTION;
附录:常用目录结构总览
/opt/mysql/mysql-8.0.20/ # 软件主目录
/usr/local/mysql -> /opt/mysql/... # 软链接
/data/mysql/mysql3306/
├── data/ # 数据文件
├── logs/ # 日志文件(error, binlog, slow)
└── my3306.cnf # 配置文件

浙公网安备 33010602011771号