服务器怎么搭建数据库

结论: 服务器搭建数据库的标准流程是六步:安装 MySQL 8.4 → 跑 mysql_secure_installation 做安全初始化 → 创建业务库与专用用户并按最小权限授权 → 调整 my.cnf 关键参数(尤其 innodb_buffer_pool_size)→ 用 bind-address 与安全组限制远程访问 → 配置 mysqldump 定时备份。其中第三步的最小授权与第五步的访问控制,是数据库不被拖库的两道关键防线。

"搭建数据库"包含三层含义:把数据库软件装上、让它安全地对外提供服务、以及保证数据可恢复。只做第一层的新手占比很高,结果是数据库裸奔在公网,常见的结局是被扫描器发现后遭遇勒索(删库要求赎金)。本文聚焦"怎么装、怎么配、怎么备份"的具体操作,至于该选 MySQL 还是 PostgreSQL、该买多大规格,属于选型层面的另一个话题。

安装前:版本选择与两条技术路线

结论:通用业务选 MySQL 8.4 LTS,需要 JSONB、GIS 地理数据、复杂分析查询或自定义数据类型时选 PostgreSQL 16。 两者都在 Ubuntu 24.04 与 CentOS Stream 9 上提供了官方源,安装成本相当。截至 2026 年,MySQL 8.4 LTS 与 PostgreSQL 16 均为各自的稳定主力版本。

对比项MySQL 8.4 LTSPostgreSQL 16
默认端口33065432
配置文件/etc/mysql/mysql.conf.d/mysqld.cnf/etc/postgresql/16/main/postgresql.conf
客户端命令mysql -u 用户 -ppsql -U 用户 -d 库名
默认认证caching_sha2_passwordscram-sha-256
权限模型用户@主机 二维授权角色(Role)+ pg_hba.conf 规则
逻辑备份工具mysqldumppg_dump / pg_dumpall
突出优势生态广、运维资料多、主从复制简单复杂查询强、JSONB/GIS 原生、扩展丰富
典型场景WordPress、Spring Boot、电商GIS、数据仓库、金融风控

安装前还需确认磁盘规划:数据库数据目录应放在独立的数据盘上(如挂载到 /data/mysql),不要与系统盘共用。理由有两点:一是数据盘可单独扩容与做快照,二是日志与数据写满系统盘会直接导致 SSH 都无法登录。

第一步:安装 MySQL 8.4

结论:Ubuntu 24.04 官方源默认提供 MySQL 8.0.x,要装 8.4 LTS 必须添加 MySQL 官方 APT 仓库。 装完第一件事是确认服务状态与版本号,而不是急着建库。

bash
# ===== Ubuntu 24.04:添加 MySQL 官方源 =====
wget https://dev.mysql.com/get/mysql-apt-config_0.8.30-1_all.deb
sudo dpkg -i mysql-apt-config_0.8.30-1_all.deb   # 交互界面中选 mysql-8.4-lts
sudo apt update
sudo apt install -y mysql-server
sudo systemctl enable --now mysql

# ===== CentOS Stream 9 / Rocky Linux 9 =====
sudo dnf install -y https://dev.mysql.com/get/mysql84-community-release-el9-1.noarch.rpm
sudo dnf install -y mysql-community-server
sudo systemctl enable --now mysqld

# ===== 验证:确认版本与监听端口 =====
mysql --version
sudo systemctl status mysql --no-pager
sudo ss -lntp | grep 3306

# 若官方源不可用,退而求其次用系统源(版本为 8.0.x)
# sudo apt install -y mysql-server

CentOS 系首次启动会在 /var/log/mysqld.log 里生成 root 临时密码,用 sudo grep 'temporary password' /var/log/mysqld.log 取出后登录并立即修改。

第二步:执行安全初始化

结论:mysql_secure_installation 是装完数据库后必须立刻执行的脚本,它一次性完成设密码策略、删匿名用户、禁 root 远程登录、删 test 库四件事。 跳过这一步的数据库,等于默认允许任意来源尝试 root 登录。

bash
sudo mysql_secure_installation

交互选项建议如下:

  • VALIDATE PASSWORD 组件:选 y。强制密码长度 ≥ 8 且含大小写、数字、符号。
  • 密码强度等级:选 2(STRONG)。生产库不要用弱密码。
  • Remove anonymous users?:选 y。匿名用户可被未授权访问利用。
  • Disallow root login remotely?:选 y。root 仅允许 localhost 登录,是防止远程爆破的关键。
  • Remove test database?:选 y。默认 test 库对所有用户可写。
  • Reload privilege tables now?:选 y。让上述改动立即生效。
bash
# 初始化后验证:root 只能本地登录
sudo mysql -e "SELECT user, host, plugin FROM mysql.user;"
# 正常应看到 root 对应 host 仅为 localhost

第三步:创建数据库与用户并最小授权

结论:永远不要让你的应用直接用 root 连库。 正确做法是为每个业务创建独立数据库与独立用户,并且只授予它真正需要的那几种权限——只读服务只给 SELECT,业务服务给 SELECT, INSERT, UPDATE, DELETE,只有运维做 DDL 变更时才临时用管理账号。

sql
-- 创建业务库:字符集统一用 utf8mb4,避免 emoji 与生僻字入库报错
CREATE DATABASE appdb
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

-- 创建应用账号:@'localhost' 表示仅允许本机连接
CREATE USER 'appuser'@'localhost'
  IDENTIFIED BY 'Str0ng!Passw0rd#2026';

-- 最小授权:只给 DML,不给 DROP / ALTER / SUPER / FILE
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'appuser'@'localhost';

-- 只读账号(给报表、BI 用)
CREATE USER 'report'@'%' IDENTIFIED BY 'An0ther!Str0ngPwd';
GRANT SELECT ON appdb.* TO 'report'@'%';

FLUSH PRIVILEGES;

-- 核对授权结果
SHOW GRANTS FOR 'appuser'@'localhost';

授权时有三条红线要守住:

  • **不要写 GRANT ALL PRIVILEGES ON .**:一旦应用被注入,. 意味着攻击者能读走同实例上所有库。
  • 不要授予 FILE、SUPER、PROCESS:这些权限可用于写文件和读取其他连接信息,是提权跳板。
  • 主机位不要用 % 通配:'appuser'@'%' 表示允许从任意 IP 连接,应改成具体内网 IP 段,如 'appuser'@'10.0.0.%'。

第四步:调整关键配置参数

结论:默认配置是按极小内存机器设计的,必须根据服务器规格调整,其中 innodb_buffer_pool_size 影响最大。 缓冲池(Buffer Pool)是 InnoDB 缓存数据与索引的内存区域,命中率直接决定磁盘 IO 压力。

ini
# /etc/mysql/mysql.conf.d/mysqld.cnf  (Ubuntu 24.04)
[mysqld]
# 数据目录:建议指向独立数据盘
datadir                  = /data/mysql

# 缓冲池:独占数据库服务器设为物理内存的 50%~70%
# 8G 机器设 5G,4G 机器设 2G;与应用同机部署时降到 40% 以下
innodb_buffer_pool_size  = 5G
innodb_buffer_pool_instances = 4

# 连接与超时
max_connections          = 300
wait_timeout             = 600
interactive_timeout      = 600

# 字符集与时区
character-set-server     = utf8mb4
collation-server         = utf8mb4_unicode_ci
default-time-zone        = '+08:00'

# 持久化与性能权衡:1 为最安全(每次提交落盘),2 为每秒刷一次
innodb_flush_log_at_trx_commit = 1
innodb_log_file_size     = 512M

# 慢查询日志:定位慢 SQL 的基础
slow_query_log           = 1
slow_query_log_file      = /var/log/mysql/mysql-slow.log
long_query_time          = 2

# 每个连接的排序缓冲,不宜设大,否则并发时内存暴涨
sort_buffer_size         = 2M
join_buffer_size         = 2M

修改后必须校验并重启(注意:innodb_buffer_pool_size 等参数需重启才生效,不能用 reload):

bash
sudo mysqld --help --verbose 2>/dev/null | grep -i 'buffer pool'   # 查默认值参考
sudo systemctl restart mysql
sudo mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
               SHOW VARIABLES LIKE 'max_connections';
               SHOW VARIABLES LIKE 'slow_query_log';"

第五步:远程访问的安全配置

结论:数据库端口绝不应直接对公网开放。bind-address 决定 MySQL 监听哪个网卡,配合云平台安全组限制来源 IP,才是安全的远程访问方式;更推荐的做法是用 SSH 隧道或内网专线。

ini
# 只监听本机:应用与数据库同机部署时用这个(默认值,最安全)
bind-address = 127.0.0.1

# 监听内网网卡:应用部署在其他服务器时,填数据库机的内网 IP
bind-address = 10.0.0.12

# 监听所有地址:等同于对全网开放,禁止在生产环境使用
# bind-address = 0.0.0.0
bash
# 修改后重启生效
sudo systemctl restart mysql
sudo ss -lntp | grep 3306        # 确认监听地址已变更

# 防火墙只放行来自应用服务器内网 IP 的连接
sudo ufw allow from 10.0.0.20 to any port 3306 proto tcp
# firewalld 写法:
# sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" \
#   source address="10.0.0.20" port port="3306" protocol="tcp" accept'
# sudo firewall-cmd --reload

# 从应用机测试连通性
mysql -h 10.0.0.12 -u appuser -p -e "SELECT 1;"

若必须跨公网管理数据库,请用 SSH 隧道代替开放端口:本地执行 ssh -L 3307:127.0.0.1:3306 user@dbserver,然后连接本机的 3307 端口,全程走加密的 SSH 通道,数据库端口无需暴露。

第六步:备份与恢复

结论:没有备份的数据库等于没有数据。mysqldump 是逻辑备份的标准工具,配合 crontab 每天全量 + 保留 7~30 天,是中小规模最实用的方案。

bash
# 全库备份:--single-transaction 保证 InnoDB 一致性且不锁表
mysqldump -u root -p --single-transaction --routines --triggers --events \
  --set-gtid-purged=OFF appdb | gzip > /backup/appdb_$(date +%F).sql.gz

# 全实例备份(含所有库与用户权限)
mysqldump -u root -p --all-databases --single-transaction \
  --routines --triggers --events | gzip > /backup/all_$(date +%F).sql.gz

# 恢复:先解压再导入
gunzip < /backup/appdb_2026-03-15.sql.gz | mysql -u root -p appdb

# 只备份表结构(用于建测试库)
mysqldump -u root -p --no-data appdb > /backup/appdb_schema.sql

# 加入定时任务:每天凌晨 2 点全量备份,保留 14 天
sudo crontab -e
0 2 * * * mysqldump -u root -p'密码' --single-transaction appdb | gzip > /backup/appdb_$(date +\%F).sql.gz
0 3 * * * find /backup -name "appdb_*.sql.gz" -mtime +14 -delete

把密码明文写进 crontab 有泄露风险,更好的方式是把凭据写进 ~/.my.cnf(权限 600)并在命令里省略 -p:

ini
# ~/.my.cnf
[mysqldump]
user=root
password=Str0ng!Passw0rd