Docker查看容器IP,docker inspect命令

前言

容器之间要互相通信,得知道容器的IP。本文讲怎么用docker inspect查看容器IP和详细信息。

一、查看容器IP

最简单的方法

docker inspect 容器名

输出一大串JSON,找IPAddress字段。

只看IP

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 容器名

直接输出IP地址,比如:172.17.0.2

查看所有运行中容器的IP

docker ps -q | xargs docker inspect -f '{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'

输出:

/mynginx - 172.17.0.2
/mymysql - 172.17.0.3
/myphp - 172.17.0.4

二、docker inspect常用用法

查看容器挂载

docker inspect -f '{{.Mounts}}' 容器名

查看容器启动命令

docker inspect -f '{{.Config.Cmd}}' 容器名

查看容器环境变量

docker inspect -f '{{.Config.Env}}' 容器名

查看容器端口映射

docker inspect -f '{{.NetworkSettings.Ports}}' 容器名

查看容器网络

docker inspect -f '{{.NetworkSettings.Networks}}' 容器名

查看容器状态

docker inspect -f '{{.State.Status}}' 容器名

查看容器启动时间

docker inspect -f '{{.State.StartedAt}}' 容器名

查看容器日志路径

docker inspect -f '{{.LogPath}}' 容器名

三、查看镜像信息

查看镜像详细信息

docker inspect 镜像名

查看镜像作者

docker inspect -f '{{.Author}}' nginx

查看镜像默认启动命令

docker inspect -f '{{.Config.Cmd}}' nginx

四、容器之间怎么通信

用容器名通信(推荐)

Docker默认网络里,容器可以用容器名互相访问:

# 在nginx容器里ping mysql
docker exec mynginx ping mysql

不用记IP,直接用容器名就行。

用自定义网络

# 创建网络
docker network create mynet

# 容器加入网络
docker run --name mysql --network mynet -d mysql:5.7
docker run --name nginx --network mynet -d nginx

五、常见场景

场景1:Nginx反向代理连PHP

nginx配置里:

fastcgi_pass php:9000;

这里的php就是容器名,Docker会自动解析成容器IP。

场景2:PHP连MySQL

<?php
$pdo = new PDO('mysql:host=mysql;dbname=mydb', 'root', '123456');
?>

host填mysql,就是MySQL容器的名字。

六、容器IP会变吗?

会的。

容器重启后,IP可能会变。所以不要硬编码IP,用容器名通信最稳。

如果要固定IP: 用自定义网络,指定静态IP。

# docker-compose.yml
services:
  mysql:
    networks:
      mynet:
        ipv4_address: 172.20.0.10

常见坑

坑1:inspect输出太多,找不到IP

解决: 用 -f 参数过滤,只看你要的字段。

坑2:容器停了就看不到IP

容器停止状态下,IPAddress是空的。

解决: 先启动容器:docker start 容器名

坑3:不同网络的容器互相ping不通

原因: 容器在不同网络里。

解决: 把它们加到同一个网络:

docker network connect mynet 容器名

坑4:用容器名ping不通

原因: 不是默认网络,或者Docker版本太老。

解决: 用自定义网络,或者直接用IP。

坑5:host网络模式看不到IP

用 --network=host 启动的容器,IP和宿主机一样。

解决: 不用查了,就是宿主机的IP。

总结

常用命令:

命令 说明
docker inspect 容器名 看容器全部信息
docker inspect -f '{{.NetworkSettings.IPAddress}}' 容器名 只看IP
docker inspect -f '{{.Mounts}}' 容器名 看挂载
docker inspect -f '{{.Config.Env}}' 容器名 看环境变量

记住: 容器之间用容器名通信,别硬编码IP,重启就变了。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 08:15 

Docker容器内时间和宿主机不一致修复

前言

Docker容器里的时间和宿主机差了8个小时,日志时间不对,定时任务也跑偏。本文讲怎么修复容器时区问题。

一、问题现象

# 宿主机时间
date
# 输出:Thu Oct  8 08:14:01 CST 2026

# 容器里时间
docker exec 容器名 date
# 输出:Thu Oct  8 00:14:01 UTC 2026

差了8个小时,因为容器默认用UTC时区。

二、查看容器时区

docker exec 容器名 date

或者:

docker exec 容器名 cat /etc/timezone

三、修复方法

方法1:挂载时区文件(推荐)

启动容器时挂载宿主机的时区文件:

docker run -v /etc/localtime:/etc/localtime:ro 镜像名

这样容器就和宿主机用同一个时区了。

方法2:设置环境变量

docker run -e TZ=Asia/Shanghai 镜像名

方法3:进容器手动改

# 进容器
docker exec -it 容器名 bash

# 装时区数据
apt-get update && apt-get install -y tzdata

# 设置时区
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
echo "Asia/Shanghai" > /etc/timezone

# 验证
date

方法4:Docker Compose设置

在docker-compose.yml里加:

services:
  app:
    image: xxx
    environment:
      - TZ=Asia/Shanghai
    volumes:
      - /etc/localtime:/etc/localtime:ro

四、PHP容器额外设置

PHP的时区和系统时区是两回事,还要改php.ini:

[Date]
date.timezone = Asia/Shanghai

或者在代码里设:

<?php
date_default_timezone_set('Asia/Shanghai');
?>

五、MySQL容器额外设置

MySQL的时区也要改:

-- 查看当前时区
SELECT @@global.time_zone;

-- 设置为东八区
SET GLOBAL time_zone = '+8:00';

永久生效改my.cnf:

[mysqld]
default-time-zone = '+8:00'

六、验证

# 宿主机时间
date

# 容器时间
docker exec 容器名 date

两个时间一致就对了。

常见坑

坑1:改了时区不生效

改了时区文件,重启容器又变回UTC了。

原因: 容器重启后文件系统重置了。

解决: 用挂载的方式,不要进容器改。

坑2:只改了系统时区,PHP时区不对

系统时间对了,但PHP date()还是错的。

原因: PHP有自己的时区设置。

解决: 改php.ini的date.timezone。

坑3:日志时间不对

日志里的时间还是UTC。

原因: 程序启动时读的时区,改了时区要重启程序。

解决: 重启容器或重启程序。

坑4:Windows/Mac Docker Desktop

Windows和Mac上Docker Desktop的时区处理不一样。

解决: 直接用TZ环境变量最稳。

坑5:时区列表找不到Asia/Shanghai

原因: 容器里没装tzdata。

解决: 先装tzdata:

apt-get install -y tzdata

总结

最稳的方法:

  1. 挂载 /etc/localtime:/etc/localtime:ro
  2. 加环境变量 TZ=Asia/Shanghai
  3. PHP改 date.timezone
  4. MySQL改 default-time-zone

记住: 时区不一致是Docker最常见的问题之一,部署完第一件事先验证时间。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 08:14 

Docker Compose部署LNMP环境完整示例

前言

手动装Nginx、PHP、MySQL太麻烦,用Docker Compose一键部署LNMP环境,几分钟搞定。

一、项目结构

lnmp/
├── docker-compose.yml
├── nginx/
│   ├── conf.d/
│   │   └── default.conf
│   └── nginx.conf
├── php/
│   └── php.ini
├── mysql/
│   └── my.cnf
└── www/
    └── index.php

二、docker-compose.yml

version: '3'

services:
  nginx:
    image: nginx:latest
    container_name: lnmp_nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./www:/var/www/html
    depends_on:
      - php
    networks:
      - lnmp

  php:
    image: php:fpm
    container_name: lnmp_php
    volumes:
      - ./www:/var/www/html
      - ./php/php.ini:/usr/local/etc/php/php.ini
    networks:
      - lnmp

  mysql:
    image: mysql:5.7
    container_name: lnmp_mysql
    ports:
      - "3306:3306"
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: mydb
    networks:
      - lnmp

networks:
  lnmp:
    driver: bridge

三、Nginx配置

nginx/conf.d/default.conf

server {
    listen       80;
    server_name  localhost;
    root   /var/www/html;
    index  index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass   php:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /var/www/html$fastcgi_script_name;
        include        fastcgi_params;
    }
}

四、PHP配置

php/php.ini

[PHP]
date.timezone = Asia/Shanghai
upload_max_filesize = 20M
post_max_size = 20M
memory_limit = 128M

五、MySQL配置

mysql/my.cnf

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci

六、测试文件

www/index.php

<?php
phpinfo();
?>

七、启动

cd lnmp
docker-compose up -d

查看状态

docker-compose ps

访问

http://localhost

能看到phpinfo页面就是成功了。

八、常用命令

命令 说明
docker-compose up -d 启动
docker-compose down 停止并删除容器
docker-compose restart 重启
docker-compose logs -f 看日志
docker-compose exec php bash 进PHP容器
docker-compose exec mysql bash 进MySQL容器

九、连接MySQL

从宿主机连接

mysql -h 127.0.0.1 -P 3306 -u root -p123456

从PHP连接

<?php
$pdo = new PDO('mysql:host=mysql;dbname=mydb', 'root', '123456');
echo "连接成功";
?>

注意:host填mysql,不是localhost,是docker-compose.yml里的服务名。

十、安装PHP扩展

进入PHP容器

docker-compose exec php bash

安装pdo_mysql

docker-php-ext-install pdo_mysql
docker-php-ext-install mysqli

重启PHP

docker-compose restart php

常见坑

坑1:Nginx报502

502 Bad Gateway,原因是PHP容器没启动,或者地址不对。

解决:确认PHP容器在运行,fastcgi_pass填服务名php:9000。

坑2:MySQL启动失败

原因:数据目录权限不对,或者密码没设。

解决:确认MYSQL_ROOT_PASSWORD设了,数据目录权限改成777。

坑3:文件修改不生效

改了www里的文件,浏览器刷新没变。

解决:确认volumes挂载了./www:/var/www/html。

坑4:端口被占用

port is already allocated,原因是宿主机80端口被占了。

解决:改端口,比如改成8080。

坑5:数据丢失

删了容器,MySQL数据没了。

解决:一定要挂载数据卷,./mysql/data:/var/lib/mysql。

总结

部署五步:建项目目录结构,写docker-compose.yml,写配置文件,docker-compose up -d启动,浏览器访问测试。

记住:数据一定要挂载,不然删容器数据就没了。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 08:13 

Docker镜像占用空间过大,清理无用镜像容器

前言

用了一段时间Docker,磁盘满了。docker images一看,一堆旧镜像和停止的容器占着空间。本文讲怎么清理Docker空间。

一、查看Docker占用空间

docker system df

输出:

TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          50        10        15GB      10GB
Containers      30        10        500MB     400MB
Local Volumes   20        5         2GB       1.5GB

RECLAIMABLE 就是可以回收的空间。

二、查看镜像列表

docker images

看REPOSITORY、TAG、SIZE列。

三、清理停止的容器

删除单个容器

docker rm 容器ID/容器名

删除所有停止的容器

docker container prune

会提示确认,输入y。

加-f强制删除

docker container prune -f

不提示直接删。

四、清理无用镜像

删除单个镜像

docker rmi 镜像ID/镜像名

删除所有悬空镜像

悬空镜像就是 <none>:<none> 那些,构建中间产生的。

docker image prune

删除所有未被使用的镜像

docker image prune -a

注意:这会删掉所有没被容器用着的镜像,小心。

五、清理无用卷

查看卷

docker volume ls

删除无用卷

docker volume prune

六、清理无用网络

docker network prune

七、一键全部清理

docker system prune

清理:

  • 停止的容器
  • 无用网络
  • 悬空镜像
  • 构建缓存

连镜像一起删

docker system prune -a

把没被用的镜像也删掉。

加时间过滤

只删24小时前的:

docker system prune -a --filter "until=24h"

八、常见清理场景

场景1:磁盘快满了

# 先看占了多少
docker system df

# 清理停止的容器
docker container prune -f

# 清理悬空镜像
docker image prune -f

# 清理无用卷
docker volume prune -f

场景2:想彻底清理

docker system prune -a -f --volumes

九、手动清理某个镜像

找到镜像ID

docker images

删除

docker rmi 镜像ID

强制删除

如果镜像被停止的容器引用了,先删容器:

docker rm 容器ID
docker rmi 镜像ID

或者强制删:

docker rmi -f 镜像ID

常见坑

坑1:删镜像报错

Error response from daemon: conflict: unable to delete image (must be forced) - image is being used by stopped container

原因: 有停止的容器在用这个镜像。

解决: 先删容器,或者强制删。

坑2:删了镜像,数据还在

镜像删了,但卷还在,数据没丢。

原因: 数据存在卷里,和镜像分开的。

这是好事! 重新起容器挂载同一个卷,数据就回来了。

坑3:docker system prune删多了

把还要用的镜像也删了。

解决: 重要镜像别删,重新pull就行。

坑4:清理完磁盘还是满的

Docker清理了,但磁盘还是100%。

原因: Docker日志文件太大了。

解决: 清理容器日志:

truncate -s 0 /var/lib/docker/containers/*/*-json.log

或者配置日志大小限制。

坑5:构建缓存占空间

docker builder prune

清理构建缓存。

十、定期清理

可以加个定时任务,每周清理一次:

crontab -e

加:

0 3 * * 0 /usr/bin/docker system prune -a -f --filter "until=168h"

每周日凌晨3点清理一周前的。

总结

常用清理命令:

命令 说明
docker system df 看占用空间
docker container prune 清理停止的容器
docker image prune 清理悬空镜像
docker volume prune 清理无用卷
docker system prune -a 一键全清

记住: 定期清理,别等磁盘满了再弄。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 08:10 

Docker容器启动失败,查看容器日志排查错误

前言

Docker容器启动后马上就退出了,不知道为什么。本文讲怎么查看容器日志,排查启动失败的原因。

一、查看容器状态

列出所有容器

docker ps -a

看STATUS列:

  • Up 就是正常运行
  • Exited (1) 就是异常退出了

查看指定容器状态

docker ps -a | grep 容器名

二、查看容器日志

基本用法

docker logs 容器名/容器ID

实时查看日志

docker logs -f 容器名

查看最后100行

docker logs --tail 100 容器名

带时间戳

docker logs -t 容器名

查看最近10分钟的日志

docker logs --since 10m 容器名

三、常见启动失败原因

原因1:程序启动就退出

比如你跑的是个命令行程序,执行完就退出了,容器当然也跟着退。

解决: 前台运行程序,别后台跑。

# 错误:后台运行
CMD service nginx start

# 正确:前台运行
CMD nginx -g "daemon off;"

原因2:配置文件错误

比如nginx配置写错了,启动失败。

日志里会有:

nginx: [emerg] unknown directive "xxx"

解决: 根据日志提示改配置。

原因3:端口被占用

宿主机的端口已经被别的程序占了。

日志里会有:

Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use

解决: 换个端口,或者把占用端口的程序关掉。

# 查谁占用了80端口
netstat -tlnp | grep :80

原因4:挂载的文件不存在

-v挂载的宿主机路径不存在。

日志里会有:

no such file or directory

解决: 先创建宿主机目录。

mkdir -p /data/www

原因5:权限问题

挂载的目录权限不对,程序读不了。

日志里会有:

Permission denied

解决: 改目录权限:

chmod 755 /data/www

原因6:环境变量没设

程序需要的环境变量没传进去。

日志里会有:

Environment variable XXX is not set

解决: 启动时传环境变量:

docker run -e MYSQL_ROOT_PASSWORD=123456 mysql

四、排查步骤

第一步:看状态

docker ps -a

确认容器是Exited状态。

第二步:看日志

docker logs 容器名

日志最后几行就是报错原因。

第三步:进容器看

如果日志不够详细,进容器里手动跑:

docker run -it 镜像名 /bin/bash

进去后手动执行启动命令,看报什么错。

第四步:检查配置

挂载的配置文件对不对,环境变量有没有。

五、常用命令汇总

命令 说明
docker ps -a 看所有容器状态
docker logs 容器名 看日志
docker logs -f 容器名 实时看日志
docker logs --tail 100 容器名 看最后100行
docker inspect 容器名 看容器详细信息
docker exec -it 容器名 /bin/bash 进运行中的容器
docker run -it 镜像 /bin/bash 用镜像开个交互式容器

六、查看容器详细信息

docker inspect 容器名

能看到挂载、环境变量、网络等所有信息。

只看挂载信息

docker inspect -f '{{.Mounts}}' 容器名

只看启动命令

docker inspect -f '{{.Config.Cmd}}' 容器名

常见坑

坑1:容器启动马上退出,日志是空的

docker logs 容器名

什么都没有。

原因: 程序本身就没输出,或者启动太早就挂了。

解决: 用 docker run -it 镜像 /bin/bash 进去手动跑。

坑2:改了配置不生效

改了挂载的配置文件,重启容器还是不生效。

原因: 容器没真正重启,或者配置文件路径不对。

解决: 强制重启:

docker restart 容器名

坑3:日志一直刷,停不下来

docker logs -f 容器名

日志一直在刷。

解决: 按 Ctrl+C 退出。

坑4:容器删除了日志就没了

容器删了,日志也跟着没了。

解决: 重要日志挂载到宿主机。

坑5:看日志找不到容器ID

容器太多,不知道哪个是哪个。

解决: 启动的时候给容器起个好记的名字:

docker run --name mynginx -d nginx

总结

排查三步:

  1. docker ps -a 看容器状态
  2. docker logs 容器名 看报错
  3. 按日志提示改问题

记住: 容器启动失败别慌,看日志就行,日志里都写了原因。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 08:01 

MySQL锁表查询,kill锁表进程

前言

网站突然卡死,查什么都慢,可能是表被锁住了。怎么查谁锁的表,怎么杀掉锁表进程?

一、查看正在执行的进程

SHOW FULL PROCESSLIST;

看State列,要是 Locked 就是锁表了。

二、查看锁表信息

查看当前锁

SELECT * FROM information_schema.INNODB_TRX;

这是InnoDB正在执行的事务。

查看锁等待

SELECT * FROM information_schema.INNODB_LOCK_WAITS;

看谁在等谁的锁。

查看具体的锁

SELECT * FROM information_schema.INNODB_LOCKS;

MySQL 8.0改成了 performance_schema.data_locks。

三、找出锁表的SQL

查看长时间运行的事务

SELECT 
    trx_id,
    trx_state,
    trx_started,
    trx_mysql_thread_id,
    TIMESTAMPDIFF(SECOND, trx_started, NOW()) as run_seconds,
    trx_query
FROM information_schema.INNODB_TRX
ORDER BY trx_started;

run_seconds 越大,跑的越久,越可能是锁表的元凶。

查看锁等待链

SELECT 
    r.trx_id as waiting_trx_id,
    r.trx_mysql_thread_id as waiting_thread,
    r.trx_query as waiting_query,
    b.trx_id as blocking_trx_id,
    b.trx_mysql_thread_id as blocking_thread,
    b.trx_query as blocking_query
FROM information_schema.INNODB_LOCK_WAITS w
JOIN information_schema.INNODB_TRX b ON b.trx_id = w.blocking_trx_id
JOIN information_schema.INNODB_TRX r ON r.trx_id = w.requesting_trx_id;

四、杀掉锁表进程

找到进程ID

从上面的查询结果里,找到 blocking_thread,就是锁表的那个连接ID。

杀掉进程

KILL 进程ID;

批量杀掉

比如杀掉所有跑了超过60秒的事务:

SELECT CONCAT('KILL ', trx_mysql_thread_id, ';') 
FROM information_schema.INNODB_TRX 
WHERE TIMESTAMPDIFF(SECOND, trx_started, NOW()) > 60;

把结果复制出来执行。

五、常用查询

查看谁在锁什么表

SELECT 
    t.table_name,
    t.table_rows,
    l.lock_type,
    l.lock_mode,
    l.lock_id,
    t2.trx_mysql_thread_id,
    t2.trx_query,
    t2.trx_started
FROM information_schema.INNODB_LOCKS l
JOIN information_schema.INNODB_TRX t2 ON l.lock_trx_id = t2.trx_id
JOIN information_schema.TABLES t ON l.lock_table = CONCAT(t.table_schema, '/', t.table_name);

查看行锁还是表锁

  • RECORD 是行锁
  • TABLE 是表锁

六、为什么会锁表

原因1:大事务没提交

开了个事务,执行了一大堆,一直没commit,锁就一直占着。

解决: 事务要短小,及时提交。

原因2:没有索引

更新/删除没走索引,会锁全表。

解决: 给where条件加索引。

原因3:DDL操作

ALTER TABLE、OPTIMIZE TABLE这些会锁表。

解决: 低峰期做,或者用pt-online-schema-change。

原因4:长查询

一条SQL跑几分钟,锁住相关行。

解决: 优化慢SQL。

七、MySQL 8.0的变化

MySQL 8.0把INNODB_LOCKS和INNODB_LOCK_WAITS废弃了,改成了performance_schema。

查看锁等待(8.0)

SELECT * FROM performance_schema.data_lock_waits;

查看锁(8.0)

SELECT * FROM performance_schema.data_locks;

常见坑

坑1:杀错进程

杀了正在正常执行的业务进程,导致业务报错。

解决: 先看清楚trx_query是什么,确认是僵尸事务再杀。

坑2:杀了又出来

杀了锁表进程,过一会儿又锁了。

原因: 程序里有死循环,或者连接池自动重连了。

解决: 找到源头,修代码。

坑3:KILL不掉

KILL 123;

进程还在,没杀掉。

原因: 事务在做rollback,需要时间。

解决: 等它回滚完,或者直接重启MySQL。

坑4:查不到锁信息

information_schema.INNODB_TRX是空的。

原因: 可能是MyISAM表,MyISAM的表锁不在InnoDB里。

MyISAM表锁查看:

SHOW OPEN TABLES WHERE In_use > 0;

坑5:锁和MDL搞混

MDL(元数据锁)不是行锁,是表结构的锁。

查看MDL锁:

SELECT * FROM performance_schema.metadata_locks;

总结

锁表排查三步:

  1. SHOW FULL PROCESSLIST 看有没有Locked
  2. information_schema.INNODB_TRX 找长事务
  3. KILL 进程ID 杀掉锁表进程

记住: 杀之前先看清楚是什么SQL,别误杀了正常业务!

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 08:00 

MySQL定时备份脚本,自动删除旧备份

前言

数据库数据很重要,必须每天自动备份。写个备份脚本,自动备份+自动删旧的,不用手动管。

一、备份脚本

完整脚本 backup_mysql.sh

#!/bin/bash

# MySQL配置
DB_USER="root"
DB_PASS="your_password"
DB_NAME="mydb"

# 备份目录
BACKUP_DIR="/data/backup/mysql"

# 保留天数
KEEP_DAYS=7

# 日期
DATE=$(date +%Y%m%d_%H%M%S)

# 备份文件名
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz"

# 创建目录
mkdir -p $BACKUP_DIR

# 备份并压缩
mysqldump -u$DB_USER -p$DB_PASS $DB_NAME | gzip > $BACKUP_FILE

# 检查备份是否成功
if [ $? -eq 0 ]; then
    echo "[$(date)] 备份成功: $BACKUP_FILE"
else
    echo "[$(date)] 备份失败!"
    exit 1
fi

# 删除7天前的旧备份
find $BACKUP_DIR -name "*.sql.gz" -mtime +$KEEP_DAYS -delete

echo "[$(date)] 旧备份清理完成"

二、脚本说明

各部分解释

部分 说明
DB_USER 数据库用户名
DB_PASS 数据库密码
DB_NAME 要备份的数据库名
BACKUP_DIR 备份存放目录
KEEP_DAYS 保留几天的备份
mysqldump 备份命令
gzip 压缩,节省空间
find -mtime +7 找7天前的文件删除

备份全部数据库

mysqldump -u$DB_USER -p$DB_PASS --all-databases | gzip > $BACKUP_FILE

备份多个数据库

mysqldump -u$DB_USER -p$DB_PASS --databases db1 db2 db3 | gzip > $BACKUP_FILE

三、设置执行权限

chmod +x /data/backup/backup_mysql.sh

四、测试脚本

/data/backup/backup_mysql.sh

看有没有备份文件生成:

ls -lh /data/backup/mysql/

五、设置定时任务

每天凌晨3点备份

crontab -e

添加:

0 3 * * * /data/backup/backup_mysql.sh >> /data/backup/backup.log 2>&1

说明:

  • 0 3 * * * 每天凌晨3点
  • >> backup.log 输出写到日志
  • 2>&1 错误也写进去

查看定时任务

crontab -l

六、备份文件恢复

恢复步骤

# 解压
gunzip < mydb_20261008_030000.sql.gz | mysql -u root -p mydb

或者先解压再恢复

# 解压
gunzip mydb_20261008_030000.sql.gz

# 恢复
mysql -u root -p mydb < mydb_20261008_030000.sql

七、更完善的脚本

带日志和邮件通知的版本

#!/bin/bash

DB_USER="root"
DB_PASS="your_password"
DB_NAME="mydb"
BACKUP_DIR="/data/backup/mysql"
KEEP_DAYS=7
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz"
LOG_FILE="$BACKUP_DIR/backup.log"

mkdir -p $BACKUP_DIR

echo "========== $(date) 开始备份 ==========" >> $LOG_FILE

# 备份
mysqldump -u$DB_USER -p$DB_PASS $DB_NAME 2>>$LOG_FILE | gzip > $BACKUP_FILE

if [ $? -eq 0 ]; then
    FILE_SIZE=$(ls -lh $BACKUP_FILE | awk '{print $5}')
    echo "[$(date)] 备份成功,文件大小: $FILE_SIZE" >> $LOG_FILE
else
    echo "[$(date)] 备份失败!" >> $LOG_FILE
    # 这里可以加邮件通知
    exit 1
fi

# 删除旧备份
find $BACKUP_DIR -name "*.sql.gz" -mtime +$KEEP_DAYS -delete
echo "[$(date)] 清理 $KEEP_DAYS 天前的旧备份完成" >> $LOG_FILE

echo "========== $(date) 备份结束 ==========" >> $LOG_FILE

常见坑

坑1:密码写在脚本里不安全

脚本里明文写了数据库密码。

解决: 用mysql配置文件:

# /root/.my.cnf
[client]
user=root
password=your_password

然后脚本里就不用写密码了:

mysqldump $DB_NAME | gzip > $BACKUP_FILE

设置权限:

chmod 600 /root/.my.cnf

坑2:备份文件太大

不压缩的话备份文件很大。

解决: 用gzip压缩,能压缩到原来的1/10。

坑3:定时任务不执行

cron里写了脚本,但没执行。

原因:

  1. 脚本没加执行权限
  2. 路径写错了
  3. 环境变量不对

解决: 脚本里用全路径,比如 /usr/bin/mysqldump。

坑4:备份完没验证

备份文件损坏了都不知道。

解决: 定期找个测试库恢复一下,看备份能不能用。

坑5:备份文件存在同一台服务器

服务器挂了,备份也没了。

解决: 把备份传到远程服务器或OSS。

# 传到远程服务器
scp $BACKUP_FILE root@192.168.1.20:/data/backup/

总结

备份三步走:

  1. 写备份脚本(mysqldump + gzip + find删旧)
  2. 加执行权限
  3. 加crontab定时任务

记住: 备份不是备份了就完了,要定期验证能不能恢复!

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:59 

MySQL自增主键不连续,解决办法

前言

删了几条数据,再插入新数据,id跳了一大截,不连续了。怎么让自增主键从1开始?

一、为什么自增主键会不连续

原因1:删除了数据

删了中间的几条,id就跳了。这是正常的,InnoDB的自增计数器不会回退。

原因2:事务回滚

插入一半回滚了,自增id已经用了,不会退回来。

原因3:批量插入部分失败

插100条,第50条失败了,前49条成功,后面的id就跳了。

原因4:TRUNCATE和DELETE的区别

TRUNCATE会重置自增计数器,DELETE不会。

二、查看当前自增值

SHOW TABLE STATUS LIKE 'users';

看 Auto_increment 字段,就是下一条要插入的id。

三、重置自增主键

方法1:修改自增值

ALTER TABLE users AUTO_INCREMENT = 1;

注意: 如果表里已有数据,会设为当前最大id+1。

方法2:清空表后重置

-- 清空表(重置自增)
TRUNCATE TABLE users;

TRUNCATE会把自增计数器重置为1。

方法3:DELETE后手动重置

-- 删除所有数据
DELETE FROM users;

-- 手动重置自增
ALTER TABLE users AUTO_INCREMENT = 1;

四、怎么让自增主键连续

问题:真的需要连续吗?

其实不需要。

自增主键只要唯一就行,不连续不影响业务。用户看到的id跳了也没关系。

如果非要连续

那只能:

  1. 导出数据
  2. 清空表
  3. 重新导入
# 导出数据
mysqldump -u root -p mydb users > users.sql

# 清空表
mysql -u root -p mydb -e "TRUNCATE TABLE users"

# 重新导入
mysql -u root -p mydb < users.sql

注意: 重新导入后id会重新从1开始,但如果表之间有外键关联,会出问题。

五、InnoDB自增的坑

坑1:重启后自增值会变

MySQL 5.7之前,InnoDB把自增值存在内存里,重启后会从当前max(id)+1重新算。

如果删了最大id的那条,重启后自增值就变小了,可能重复。

MySQL 8.0修复了这个问题,把自增值持久化到redo log了。

坑2:批量插入会跳很多id

一次性插入很多数据,中间失败了,id跳了一大截。

解决: 不要批量插,一条条插。

坑3:自增步长

默认步长是1,可以改:

SHOW VARIABLES LIKE 'auto_increment_increment';

一般主从复制时会设不同步长,防止id冲突。

六、常见问题

问题1:自增主键突然跳到很大

突然从100跳到10000,怎么回事?

可能原因:

  1. 批量插入失败了
  2. 有人手动改了AUTO_INCREMENT
  3. 主从同步导致的

问题2:自增主键重复了

ERROR 1062 (23000): Duplicate entry '100' for key 'PRIMARY'

原因: 重启后自增值变小了,和已有数据冲突。

解决: 手动设大一点:

ALTER TABLE users AUTO_INCREMENT = 10000;

问题3:删除数据后id不连续

这是正常现象,不用管。

常见坑

坑1:TRUNCATE和DELETE搞混

DELETE FROM users 不会重置自增。
TRUNCATE TABLE users 会重置自增。

记住: 想重置自增用TRUNCATE。

坑2:外键约束导致TRUNCATE失败

ERROR 1701 (42000): Cannot truncate a table referenced in a foreign key constraint

解决: 先关外键检查:

SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE TABLE users;
SET FOREIGN_KEY_CHECKS = 1;

坑3:重置自增后插入报错

设AUTO_INCREMENT=1,但表里已经有id=1的数据了。

解决: 设成max(id)+1:

SELECT MAX(id) FROM users;
-- 假设max(id)=100
ALTER TABLE users AUTO_INCREMENT = 101;

总结

记住几点:

  1. 自增主键不连续是正常的,不用纠结
  2. TRUNCATE会重置自增,DELETE不会
  3. 重置自增用 ALTER TABLE t AUTO_INCREMENT = n
  4. MySQL 8.0之前重启会丢自增值,要注意

别追求id连续,没意义,唯一就行。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:58 

MySQL删除重复数据,保留一条

前言

表里有重复数据,同一个用户存了好几条。怎么删除重复数据,只保留一条?

一、先查有哪些重复数据

按字段查重复

SELECT name, COUNT(*) as cnt 
FROM users 
GROUP BY name 
HAVING cnt > 1;

查重复的完整记录

SELECT * FROM users 
WHERE name IN (
    SELECT name FROM users 
    GROUP BY name 
    HAVING COUNT(*) > 1
)
ORDER BY name;

二、删除重复数据,保留一条

方法1:用自连接(推荐)

DELETE u1 FROM users u1
INNER JOIN users u2
WHERE u1.id > u2.id AND u1.name = u2.name;

意思: 同一个name,id大的删掉,保留id小的。

方法2:用NOT IN

DELETE FROM users 
WHERE id NOT IN (
    SELECT min_id FROM (
        SELECT MIN(id) as min_id 
        FROM users 
        GROUP BY name
    ) as tmp
);

方法3:用临时表

-- 第一步:建临时表存要保留的id
CREATE TABLE tmp AS
SELECT MIN(id) as min_id FROM users GROUP BY name;

-- 第二步:删除不在临时表里的
DELETE FROM users WHERE id NOT IN (SELECT min_id FROM tmp);

-- 第三步:删临时表
DROP TABLE tmp;

三、按多个字段去重

比如name和email都重复才算重复:

DELETE u1 FROM users u1
INNER JOIN users u2
WHERE u1.id > u2.id 
AND u1.name = u2.name 
AND u1.email = u2.email;

四、保留最新的一条

不是保留id最小的,而是保留最新创建的:

DELETE u1 FROM users u1
INNER JOIN users u2
WHERE u1.created_at < u2.created_at 
AND u1.name = u2.name;

五、批量去重前先备份

重要! 删之前先备份:

CREATE TABLE users_bak AS SELECT * FROM users;

确认没问题再删。

六、怎么防止重复数据

加唯一索引

ALTER TABLE users ADD UNIQUE INDEX uk_name (name);

加了唯一索引,重复数据就插不进去了。

插入前先查

// PHP示例
$exists = $db->query("SELECT id FROM users WHERE name = '$name'");
if ($exists) {
    echo "已存在";
} else {
    $db->query("INSERT INTO users ...");
}

用INSERT IGNORE

INSERT IGNORE INTO users (name) VALUES ('张三');

重复了就忽略,不报错。

用ON DUPLICATE KEY UPDATE

INSERT INTO users (name, count) VALUES ('张三', 1)
ON DUPLICATE KEY UPDATE count = count + 1;

重复了就更新,不插入新的。

常见坑

坑1:删完发现数据没了

删重复的时候把正常数据也删了。

原因: 关联条件写错了。

解决: 先备份,再用SELECT确认要删哪些:

SELECT u1.* FROM users u1
INNER JOIN users u2
WHERE u1.id > u2.id AND u1.name = u2.name;

确认没问题再把SELECT改成DELETE。

坑2:大表删太慢

几百万条数据,删半天删不完。

解决: 分批删,每次删1000条:

DELETE FROM users WHERE ... LIMIT 1000;

坑3:自连接删不干净

有的重复数据没删掉。

原因: 字段值有NULL,NULL=NULL是unknown。

解决: 加NULL判断:

DELETE u1 FROM users u1
INNER JOIN users u2
WHERE u1.id > u2.id 
AND (u1.name = u2.name OR (u1.name IS NULL AND u2.name IS NULL));

坑4:报错"You can't specify target table for update in FROM clause"

MySQL不允许先查再删同一张表。

解决: 套一层临时表:

DELETE FROM users 
WHERE id NOT IN (
    SELECT min_id FROM (
        SELECT MIN(id) as min_id FROM users GROUP BY name
    ) as tmp
);

总结

去重三步:

  1. 先查:GROUP BY ... HAVING COUNT(*) > 1
  2. 再确认:SELECT出来看哪些要删
  3. 最后删:自连接DELETE

记住: 删之前务必备份!

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:57 

MySQL查看慢查询日志,long_query_time参数

前言

网站突然变慢,不知道哪条SQL拖后腿。开慢查询日志,把跑得慢的SQL都抓出来优化。

一、什么是慢查询日志

慢查询日志(slow query log)记录执行时间超过阈值的SQL语句。

作用: 找到慢SQL,优化它们。

二、查看是否开启

SHOW VARIABLES LIKE 'slow_query_log';
Variable_name Value
slow_query_log OFF

OFF就是没开。

三、开启慢查询日志

方法1:临时开启(重启失效)

-- 开启
SET GLOBAL slow_query_log = ON;

-- 设置阈值(超过2秒算慢)
SET GLOBAL long_query_time = 2;

方法2:永久开启

改my.cnf:

[mysqld]
# 开启慢查询
slow_query_log = 1

# 慢查询阈值(秒)
long_query_time = 2

# 慢查询日志文件位置
slow_query_log_file = /var/log/mysql/slow.log

# 没走索引的SQL也记下来(可选)
log_queries_not_using_indexes = 1

重启MySQL:

systemctl restart mysqld

四、查看慢查询日志

直接看文件

tail -f /var/log/mysql/slow.log

用mysqldumpslow分析

MySQL自带的分析工具:

# 按查询时间排序,取前10
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

常用参数:

参数 说明
-s t 按时间排序
-s c 按次数排序
-s l 按锁时间排序
-t 10 取前10条
-g 过滤关键词

示例:

# 按次数最多的排
mysqldumpslow -s c -t 20 /var/log/mysql/slow.log

# 只看select语句
mysqldumpslow -g "select" /var/log/mysql/slow.log

五、用pt-query-digest分析

更专业的分析工具(需要安装):

pt-query-digest /var/log/mysql/slow.log

输出更详细的统计报告。

六、常用参数说明

参数 默认值 说明
slow_query_log OFF 是否开启
long_query_time 10 慢查询阈值(秒)
slow_query_log_file 主机名-slow.log 日志文件位置
log_queries_not_using_indexes OFF 没走索引的也记
log_output FILE 日志输出方式(FILE/TABLE)

七、优化慢SQL

找到慢SQL后怎么优化:

1. 加索引

EXPLAIN SELECT * FROM users WHERE name = '张三';

看type是不是ALL,是ALL说明没走索引。

2. 避免select *

只查需要的字段:

-- 别这样
SELECT * FROM users;

-- 这样
SELECT id, name FROM users;

3. 避免大表全表扫描

加where条件,加limit。

4. 优化分页

大表分页越查越慢,用游标分页。

常见坑

坑1:long_query_time设太小

设成0.1秒,日志文件爆炸,全是慢SQL。

建议: 生产环境设1-2秒。

坑2:日志文件越来越大

慢查询日志一直写,磁盘满了。

解决: 用logrotate切割日志。

坑3:开启慢查询影响性能

开慢查询本身有性能损耗。

解决: 排查完就关掉,或者用低采样率。

坑4:long_query_time不生效

改了参数,但还是记录所有SQL。

原因: 连接没断开,用的还是旧参数。

解决: 重新连接MySQL。

坑5:log_output=TABLE占满系统表

把慢查询写到mysql.slow_log表,表越来越大。

解决: 定期清理:

TRUNCATE TABLE mysql.slow_log;

总结

开启三步:

  1. SET GLOBAL slow_query_log = ON
  2. SET GLOBAL long_query_time = 2
  3. 看日志:mysqldumpslow -s t -t 10 slow.log

记住: 慢查询日志是优化数据库的第一步,先找到慢SQL再优化。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:55 

MySQL字符集设置,utf8和utf8mb4区别

前言

存个emoji表情,MySQL报错" Incorrect string value",乱码了。这就是字符集没设对。

一、utf8和utf8mb4区别

字符集 最多字节 支持表情 说明
utf8 3字节 不支持 只能存BMP字符
utf8mb4 4字节 支持 完整UTF-8

注意: MySQL的utf8是阉割版,真正的UTF-8是utf8mb4。

为什么要用utf8mb4

存emoji表情(😀🍔🚀),utf8存不了,会报错。

ERROR 1366 (HY000): Incorrect string value: '\xF0\x9F\x98\x80' for column 'content'

二、查看当前字符集

SHOW VARIABLES LIKE 'character_set%';

输出:

Variable_name Value
character_set_server utf8mb4
character_set_database utf8
character_set_client utf8

三、设置字符集

1. 改my.cnf

[mysqld]
# 服务器字符集
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

重启MySQL:

systemctl restart mysqld

2. 建库时指定

CREATE DATABASE mydb 
DEFAULT CHARACTER SET utf8mb4 
COLLATE utf8mb4_general_ci;

3. 建表时指定

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

4. 改已有库字符集

ALTER DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

5. 改已有表字符集

ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

四、连接字符集

连接时也要设对,不然还是乱码。

PHP连接时设置

mysqli_set_charset($conn, 'utf8mb4');

连接后执行SQL

SET NAMES utf8mb4;

五、collation排序规则

规则 说明
utf8mb4_general_ci 不区分大小写,快
utf8mb4_unicode_ci 不区分大小写,准
utf8mb4_bin 区分大小写,二进制

推荐用utf8mb4_general_ci,快。

六、常见问题

问题1:存emoji报错

原因: 字段是utf8不是utf8mb4。

解决: 改成utf8mb4。

问题2:中文乱码

原因: 连接字符集不对。

解决: 连接后执行 SET NAMES utf8mb4。

问题3:like查询不区分大小写

原因: 用了_ci结尾的排序规则。

解决: 改用_bin。

常见坑

坑1:只改了表,没改库

库是latin1,表是utf8mb4,导数据还是乱码。

解决: 库、表、连接都要统一字符集。

坑2:改了表字符集,数据还是乱

改了表,但旧数据已经存成latin1了。

解决: 需要转码:

ALTER TABLE t MODIFY c BLOB;
ALTER TABLE t MODIFY c TEXT CHARACTER SET utf8mb4;

坑3:utf8和utf8mb4混用

有的表utf8,有的表utf8mb4,联表查询报错。

解决: 全库统一用utf8mb4。

坑4:mysqlclient不支持utf8mb4

老版本客户端不支持utf8mb4。

解决: 升级MySQL客户端。

总结

记住三点:

  1. 数据库、表、连接全部用utf8mb4
  2. 排序规则用utf8mb4_general_ci
  3. 存emoji必须用utf8mb4

别用utf8了,直接上utf8mb4。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:54 

MySQL主从复制搭建,一主多从配置

前言

一台数据库扛不住读写压力,怎么办?搭主从复制,主库写、从库读,分担压力。

一、主从复制原理

原理:

  1. 主库把写操作写进binlog
  2. 从库IO线程读主库binlog,写进中继日志(relay log)
  3. 从库SQL线程读中继日志,重放SQL

作用:

  1. 读写分离,分担主库压力
  2. 数据备份,主库挂了从库顶上
  3. 异地容灾

二、准备工作

环境:

角色 IP MySQL版本
主库 192.168.1.10 5.7
从库1 192.168.1.11 5.7
从库2 192.168.1.12 5.7

要求:

  1. MySQL版本一致
  2. 主库开启binlog
  3. 主从时间同步

三、配置主库

1. 改my.cnf

[mysqld]
# 服务ID(唯一)
server_id = 1

# 开启binlog
log_bin = mysql-bin

# binlog格式
binlog_format = ROW

# 只复制哪些库(可选)
# binlog_do_db = mydb

# 忽略哪些库(可选)
# binlog_ignore_db = mysql

2. 重启主库

systemctl restart mysqld

3. 创建复制用户

CREATE USER 'repl'@'192.168.1.%' IDENTIFIED BY 'repl123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%';
FLUSH PRIVILEGES;

4. 查看主库状态

SHOW MASTER STATUS;

输出:

File Position
mysql-bin.000001 156

记住File和Position,后面从库要用。

5. 锁表导数据

FLUSH TABLES WITH READ LOCK;

开另一个终端导出数据:

mysqldump -u root -p --all-databases --master-data=2 > all.sql

解锁:

UNLOCK TABLES;

四、配置从库1

1. 改my.cnf

[mysqld]
# 服务ID(唯一,和主库不同)
server_id = 2

# 中继日志
relay_log = relay-bin

2. 重启从库

systemctl restart mysqld

3. 导入主库数据

mysql -u root -p < all.sql

4. 关联主库

CHANGE MASTER TO
MASTER_HOST='192.168.1.10',
MASTER_USER='repl',
MASTER_PASSWORD='repl123456',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=156;

5. 开启从库

START SLAVE;

6. 查看状态

SHOW SLAVE STATUS\G

看两个值:

Slave_IO_Running: Yes
Slave_SQL_Running: Yes

都是Yes就成功了。

五、配置从库2

和从库1一样,只是server_id改成3:

[mysqld]
server_id = 3
relay_log = relay-bin

然后重复上面的步骤3-6。

六、验证主从同步

主库插入数据

CREATE TABLE test (id INT);
INSERT INTO test VALUES (1);

从库查

SELECT * FROM test;

能查到就同步成功了。

七、常用操作

查看从库状态

SHOW SLAVE STATUS\G

停止从库

STOP SLAVE;

重置从库

RESET SLAVE;

查看主库有哪些从库

SHOW SLAVE HOSTS;

常见坑

坑1:server_id重复

主库和从库server_id一样,复制失败。

解决: 每个MySQL实例server_id必须唯一。

坑2:防火墙挡了3306

从库连不上主库。

解决: 主库开放3306端口。

坑3:复制用户权限不够

解决: 复制用户需要REPLICATION SLAVE权限。

坑4:数据不一致

主从数据对不上。

原因:

  1. 从库写了数据
  2. 主库跳过了错误
  3. 大事务导致延迟

解决: 从库只读:

[mysqld]
read_only = 1

坑5:从库延迟很大

主库写太快,从库追不上。

解决:

  1. 用半同步复制
  2. 从库硬件升级
  3. 拆分更多从库

总结

搭建步骤:

  1. 主库开启binlog,设server_id=1
  2. 主库创建复制用户
  3. 主库锁表导出数据
  4. 从库改server_id,导入数据
  5. 从库关联主库,START SLAVE
  6. 验证两个Yes

记住: 一主多从配置简单,关键是server_id唯一、binlog格式一致。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:53 

MySQL报错"Too many connections"解决

前言

网站突然打不开,MySQL报"Too many connections",连接数满了。本文讲怎么排查和解决。

报错长什么样

ERROR 1040 (00000): Too many connections

意思是MySQL连接数超过最大限制了。

一、先紧急处理

查看当前连接数

SHOW STATUS LIKE 'Threads_connected';

查看最大连接数

SHOW VARIABLES LIKE 'max_connections';

默认一般是151或者100。

临时调大连接数

SET GLOBAL max_connections = 1000;

马上生效,不用重启。

二、查看谁占了连接

查看所有连接

SHOW FULL PROCESSLIST;

按用户统计

SELECT user, COUNT(*) FROM information_schema.processlist GROUP BY user;

按IP统计

SELECT SUBSTRING_INDEX(host, ':', 1) AS ip, COUNT(*) 
FROM information_schema.processlist 
GROUP BY ip;

杀掉多余连接

-- 杀掉Sleep的连接
KILL 连接ID;

批量杀:

SELECT CONCAT('KILL ', id, ';') FROM information_schema.processlist 
WHERE user = 'www' AND command = 'Sleep';

三、永久修改最大连接数

改my.cnf:

[mysqld]
max_connections = 1000

重启MySQL:

systemctl restart mysqld

四、为什么连接数会满

原因1:程序没关连接

每查一次数据库就新开一个连接,用完不关,连接越积越多。

解决:

  1. 用连接池
  2. 用完及时关连接

原因2:慢SQL占着连接

一条SQL跑10秒,请求一多,连接就占满了。

解决: 优化慢SQL,加快查询速度。

原因3:max_connections太小

默认151,大流量网站不够用。

解决: 调大到500或1000。

原因4:Sleep连接太多

大量空闲连接占着位置。

解决: 调小wait_timeout:

[mysqld]
wait_timeout = 60
interactive_timeout = 60

空闲60秒自动断开。

五、排查步骤

第一步:确认是不是真的满了

SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';

第二步:看谁占了连接

SHOW FULL PROCESSLIST;

第三步:找原因

是慢SQL?还是程序泄漏?还是连接数太小?

第四步:紧急处理

SET GLOBAL max_connections = 1000;

或者杀掉Sleep连接。

常见坑

坑1:改了配置不生效

改了my.cnf,重启了,还是151。

原因: 改错配置文件了。

解决: 确认MySQL读的是哪个配置文件:

mysql --help | grep my.cnf

坑2:max_connections调太大

调到10000,结果MySQL启动不了。

原因: 每个连接都要占内存,太多会把内存吃满。

解决: 一般500-1000够用了,别调太大。

坑3:连接泄漏没解决

调大了max_connections,过几天又满了。

原因: 程序有连接泄漏,没根本解决。

解决: 查代码,修连接泄漏问题。

坑4:max_user_connections限制

单个用户连接数也有限制。

查看:

SHOW VARIABLES LIKE 'max_user_connections';

总结

紧急处理三步:

  1. SHOW FULL PROCESSLIST 看谁占连接
  2. 杀掉多余连接
  3. 调大 max_connections

根本解决: 优化慢SQL + 修连接泄漏 + 用连接池。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:52 

MySQL开启binlog日志,恢复数据教程

前言

误删了数据,有备份但太老了,怎么办?开启binlog可以恢复到任意时间点的数据。

一、什么是binlog

binlog是MySQL的二进制日志,记录所有写操作(增删改)。

作用:

  1. 数据恢复
  2. 主从复制

二、开启binlog

查看是否开启

SHOW VARIABLES LIKE 'log_bin';
Variable_name Value
log_bin OFF

OFF就是没开。

开启方法

改my.cnf:

[mysqld]
# 开启binlog
log_bin = /var/log/mysql/mysql-bin

# 服务ID
server_id = 1

# binlog格式(推荐row)
binlog_format = ROW

# 保留7天
expire_logs_days = 7

# 单个文件最大1G
max_binlog_size = 1G

重启MySQL:

systemctl restart mysqld

验证开启成功

SHOW VARIABLES LIKE 'log_bin';

显示ON就是开了。

三、查看binlog文件

SHOW BINARY LOGS;

输出:

Log_name File_size
mysql-bin.000001 123456
mysql-bin.000002 234567

四、恢复数据

场景:误删了表,要恢复

第一步:找到要恢复的位置

先看binlog内容:

mysqlbinlog /var/log/mysql/mysql-bin.000002

找到误操作的位置点(position)。

第二步:恢复到备份点

先恢复最近的全量备份:

mysql -u root -p < backup.sql

第三步:恢复binlog

从备份点开始,恢复binlog到误操作前:

mysqlbinlog --start-position=备份点position --stop-position=误操作前position /var/log/mysql/mysql-bin.000002 | mysql -u root -p

按时间恢复

mysqlbinlog --start-datetime="2026-10-08 07:00:00" --stop-datetime="2026-10-08 07:30:00" /var/log/mysql/mysql-bin.000002 | mysql -u root -p

五、常用操作

刷新binlog(新开一个文件)

FLUSH LOGS;

删除旧binlog

-- 删除指定文件之前的
PURGE BINARY LOGS TO 'mysql-bin.000010';

-- 删除7天前的
PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 7 DAY);

查看当前binlog位置

SHOW MASTER STATUS;

六、binlog格式

格式 说明 优缺点
STATEMENT 记录SQL语句 日志小,但可能不一致
ROW 记录每行变化 日志大,但精确
MIXED 混合 折中

推荐用ROW,最安全。

常见坑

坑1:binlog没开就想恢复

原因: 事前没开启binlog。

解决: 现在就去开,不然出事就晚了。

坑2:binlog格式不对

用STATEMENT格式,恢复后数据不一致。

解决: 用ROW格式。

坑3:binlog占满磁盘

binlog一直写,磁盘满了。

解决: 设 expire_logs_days = 7,自动删旧的。

坑4:恢复顺序错了

先恢复binlog再恢复备份,数据更旧了。

正确顺序: 先恢复全量备份 → 再恢复binlog增量。

坑5:mysqlbinlog命令找不到

原因: MySQL环境变量没配。

解决: 用全路径:

/usr/local/mysql/bin/mysqlbinlog

总结

开启binlog三步:

  1. 改my.cnf加 log_bin
  2. 重启MySQL
  3. 验证 SHOW VARIABLES LIKE 'log_bin'

记住: 生产环境一定要开binlog,不然出事就完蛋。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:50 

MySQL查看数据库大小,表占用空间

前言

磁盘快满了,不知道哪个库哪个表占空间大。本文教你查MySQL数据库和表的大小。

一、查看所有数据库大小

SELECT 
    table_schema AS '数据库名',
    ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS '大小(MB)'
FROM information_schema.tables
GROUP BY table_schema
ORDER BY SUM(data_length + index_length) DESC;

输出:

数据库名 大小(MB)
mydb 512.34
test 128.56
mysql 10.24

二、查看某个数据库的所有表大小

SELECT 
    table_name AS '表名',
    ROUND(((data_length + index_length) / 1024 / 1024), 2) AS '大小(MB)',
    table_rows AS '行数'
FROM information_schema.tables
WHERE table_schema = 'mydb'
ORDER BY (data_length + index_length) DESC;

把 mydb 换成你的数据库名。

三、查看单个表大小

SELECT 
    table_name AS '表名',
    ROUND((data_length) / 1024 / 1024, 2) AS '数据大小(MB)',
    ROUND((index_length) / 1024 / 1024, 2) AS '索引大小(MB)',
    table_rows AS '行数'
FROM information_schema.tables
WHERE table_schema = 'mydb' AND table_name = 'users';

四、查看所有表大小(按大小排序)

SELECT 
    table_schema AS '数据库',
    table_name AS '表名',
    ROUND(((data_length + index_length) / 1024 / 1024), 2) AS '大小(MB)',
    table_rows AS '行数'
FROM information_schema.tables
ORDER BY (data_length + index_length) DESC
LIMIT 20;

只看前20大的表。

五、用命令行查看

查看数据目录

du -sh /var/lib/mysql/

查看某个库的大小

du -sh /var/lib/mysql/mydb/

查看所有库的大小

du -sh /var/lib/mysql/*/

六、常用场景

场景1:磁盘满了,找大表

SELECT 
    table_schema AS '数据库',
    table_name AS '表名',
    ROUND(((data_length + index_length) / 1024 / 1024), 2) AS '大小(MB)'
FROM information_schema.tables
ORDER BY (data_length + index_length) DESC
LIMIT 10;

找出最大的10个表。

场景2:表很大,想知道数据和索引各占多少

SELECT 
    table_name AS '表名',
    ROUND(data_length / 1024 / 1024, 2) AS '数据(MB)',
    ROUND(index_length / 1024 / 1024, 2) AS '索引(MB)'
FROM information_schema.tables
WHERE table_schema = 'mydb';

场景3:清理无用数据,释放空间

删了很多数据,但磁盘空间没释放。

原因: InnoDB删数据后不会自动释放磁盘空间。

解决: 优化表:

OPTIMIZE TABLE users;

常见坑

坑1:table_rows不准

InnoDB的table_rows是估算值,不是精确值。

原因: InnoDB是多版本的,统计信息不精确。

解决: 要精确行数用 SELECT COUNT(*) FROM 表名;

坑2:删了数据空间没释放

DELETE删了很多行,但文件大小没变。

原因: InnoDB的表空间不会自动收缩。

解决: OPTIMIZE TABLE 表名; 或者重建表。

坑3:临时表占空间

performance_schema等系统库也占空间。

解决: 正常现象,不用管。

坑4:ibdata1文件很大

共享表空间文件很大,但不知道里面是什么。

原因: 所有InnoDB表都存在一个文件里。

解决: 开 innodb_file_per_table,每个表独立文件。

总结

常用查询:

  1. 查所有库大小:GROUP BY table_schema
  2. 查某库所有表:WHERE table_schema='库名'
  3. 查某表大小:WHERE table_schema='库名' AND table_name='表名'

记住: 磁盘满了先查information_schema.tables找大表。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:49 

MySQL删除表、清空表,truncate和delete区别

前言

清空表数据,用DELETE还是TRUNCATE?删表用DROP?很多人搞混,本文讲清楚区别。

三种操作

1. DELETE:删行

-- 删指定行
DELETE FROM users WHERE id = 1;

-- 删全表
DELETE FROM users;

特点:

  • 一行一行删,慢
  • 可以加WHERE条件
  • 可以回滚(在事务里)
  • 自增ID不重置,继续从之前的数开始
  • 会写binlog

2. TRUNCATE:清空表

TRUNCATE TABLE users;

特点:

  • 直接删表重建,快
  • 不能加WHERE条件
  • 不能回滚
  • 自增ID重置,从1开始
  • 比DELETE快很多

3. DROP:删表

DROP TABLE users;

特点:

  • 表结构+数据全删
  • 表都没了
  • 最快

对比表

对比项 DELETE TRUNCATE DROP
删什么 删行 删表重建 删表
速度 慢 快 最快
WHERE 支持 不支持 不支持
回滚 可以 不可以 不可以
自增ID 不重置 重置 表都没了
表结构 保留 保留 删除
写binlog 是 是(默认) 是

什么时候用哪个

用DELETE

  • 只删部分数据(带WHERE)
  • 需要回滚
  • 数据量小

用TRUNCATE

  • 清空全表数据
  • 数据量大,要快
  • 不需要回滚

用DROP

  • 表不要了
  • 表结构也删

常见坑

坑1:DELETE删全表很慢

DELETE FROM users;

100万行删半天。

解决: 清空全表用 TRUNCATE TABLE users;

坑2:TRUNCATE不能回滚

执行TRUNCATE后想后悔,回不去了。

解决: 执行前先备份,或者用DELETE(慢但能回滚)。

坑3:TRUNCATE自增ID重置

清空表后,自增ID从1开始了。

原因: TRUNCATE会重建表。

解决: 如果不想重置自增ID,用DELETE。

坑4:外键约束导致TRUNCATE失败

ERROR 1701 (42000): Cannot truncate a table referenced in a foreign key constraint

原因: 有其他表的外键关联到这个表。

解决: 先关外键检查:

SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE TABLE users;
SET FOREIGN_KEY_CHECKS = 1;

坑5:DELETE不写WHERE删全表

手滑了,没写WHERE,把全表删了。

解决: 执行DELETE前,先SELECT一下看条件对不对。

性能对比

操作 10万行 100万行
DELETE全表 几十秒 几分钟
TRUNCATE 0.01秒 0.01秒
DROP 0.01秒 0.01秒

TRUNCATE和DROP都是秒级,DELETE要逐行删。

总结

一句话总结:

  • 删部分数据 → DELETE
  • 清空全表 → TRUNCATE
  • 表不要了 → DROP

记住: 清空表别用DELETE,太慢了。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:48 

MySQL优化查询速度,explain分析执行计划

前言

SQL查得慢,不知道为什么慢。用EXPLAIN看MySQL怎么执行这条SQL,就能找到问题在哪。

一、EXPLAIN怎么用

EXPLAIN SELECT * FROM users WHERE name = '张三';

输出很多列,重点看这几个:id、select_type、table、type、key、rows、Extra。

二、重点列详解

1. type(访问类型)

最重要的一列,看SQL查得快不快。

从好到差:

type 说明 速度
system 表只有一行 最快
const 主键或唯一索引查一次 很快
eq_ref 联表时主键关联 很快
ref 非唯一索引查 快
range 索引范围扫描 中
index 扫整个索引树 慢
ALL 全表扫描 最慢

目标: 至少达到range,最好是ref以上。

如果type是ALL,就是全表扫描,必须优化。

2. key(实际用到的索引)

key: NULL

说明没用索引。

key: idx_name

说明用到了idx_name索引。

3. rows(扫描行数)

MySQL预估要扫描多少行。

rows越大,越慢。

4. Extra(额外信息)

常见的:

  • Using where:WHERE过滤
  • Using index:覆盖索引,不用回表,好
  • Using filesort:需要额外排序,不好
  • Using temporary:用了临时表,不好

三、常见问题

问题1:type=ALL,全表扫描

原因: 没加索引,或者索引失效。

解决: 给WHERE条件的字段加索引。

问题2:key=NULL,没用索引

原因:

  1. 没建索引
  2. 索引失效了(函数、类型转换、前导模糊查询等)

解决: 建正确的索引,避免索引失效写法。

问题3:Using filesort

原因: ORDER BY的字段没走索引。

解决: 给ORDER BY的字段加索引。

问题4:Using temporary

原因: GROUP BY或DISTINCT用了临时表。

解决: 给GROUP BY的字段加索引。

四、实战案例

慢SQL

SELECT * FROM orders WHERE user_id = 100 ORDER BY create_time DESC LIMIT 10;

EXPLAIN结果:

id select_type table type key rows Extra
1 SIMPLE orders ALL NULL 100000 Using where; Using filesort

问题:

  1. type=ALL,全表扫描
  2. key=NULL,没用索引
  3. rows=100000,扫了10万行
  4. Using filesort,还要额外排序

优化

加联合索引:

ALTER TABLE orders ADD INDEX idx_userid_createtime (user_id, create_time);

再EXPLAIN:

id select_type table type key rows Extra
1 SIMPLE orders ref idx_userid_createtime 10 Using where

优化效果:

  1. type变成ref
  2. 用到了索引
  3. rows从10万变成10
  4. 没有filesort了

五、常用优化技巧

1. 避免SELECT *

只查需要的列,能用上覆盖索引。

2. WHERE条件加索引

经常查询的字段加索引。

3. 联合索引最左前缀

联合索引 (a,b,c),查询条件要从最左列开始。

4. 避免索引失效

  • 不要对索引字段用函数
  • 不要隐式类型转换
  • 不要前导模糊查询 like '%xxx'

总结

EXPLAIN看这三点:

  1. type:是不是全表扫描
  2. key:有没有用到索引
  3. rows:扫描了多少行

记住: 慢SQL先EXPLAIN,找到问题再优化。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:47 

MySQL远程连接失败,权限和防火墙问题

前言

本地能连MySQL,远程连接就报错。常见原因:用户没授权、防火墙没开、MySQL只监听本地。

报错长什么样

ERROR 2003 (HY000): Can't connect to MySQL server on 'xxx.xxx.xxx.xxx'

或者:

ERROR 1130 (HY000): Host 'xxx.xxx.xxx.xxx' is not allowed to connect to this MySQL server

原因一:用户没授权远程登录

排查

SELECT user, host FROM mysql.user;

看root用户的host是 localhost 还是 %。

如果是 localhost,就只能本地登录。

解决

授权远程登录:

-- 方法1:授权root所有IP
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '你的密码';

-- 方法2:只允许某个IP
GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.1.100' IDENTIFIED BY '你的密码';

-- 刷新
FLUSH PRIVILEGES;

原因二:防火墙没开3306端口

排查

在本地服务器上测试:

netstat -tlnp | grep 3306

看MySQL监听的是 127.0.0.1:3306 还是 0.0.0.0:3306。

如果是 127.0.0.1:3306,说明只监听本地。

解决防火墙

CentOS7 firewalld

# 开3306端口
firewall-cmd --permanent --add-port=3306/tcp

# 重载
firewall-cmd --reload

Ubuntu ufw

ufw allow 3306/tcp

原因三:MySQL只监听本地

排查

netstat -tlnp | grep 3306

如果显示 127.0.0.1:3306,就是只监听本地。

解决

改my.cnf:

[mysqld]
bind-address = 0.0.0.0

注释掉 skip-networking(如果有的话)。

重启MySQL:

systemctl restart mysqld

原因四:云服务器安全组

阿里云、腾讯云等云服务器,除了系统防火墙,还有安全组。

解决

在云服务器控制台,找到安全组,放行3306端口。

原因五:MySQL版本问题

MySQL 8.0默认用 caching_sha2_password,老客户端不支持。

解决

创建用户时指定老的加密方式:

CREATE USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '你的密码';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
FLUSH PRIVILEGES;

排查步骤

第一步:本地能连吗

先在服务器上本地连一下:

mysql -u root -p

本地能连,说明MySQL本身没问题。

第二步:看MySQL监听地址

netstat -tlnp | grep 3306

第三步:防火墙开了吗

firewall-cmd --list-ports

看3306在不在。

第四步:远程telnet测试

在本地电脑上测试:

telnet 服务器IP 3306

如果连不上,就是网络/防火墙问题。

常见坑

坑1:改了授权忘了刷新

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';

改完就退出,结果还是连不上。

解决: 执行 FLUSH PRIVILEGES;

坑2:bind-address没改

授权了,防火墙也开了,还是连不上。

原因: MySQL只监听本地。

解决: 改 bind-address = 0.0.0.0

坑3:安全组没开

系统防火墙开了,云服务器安全组没开。

解决: 去云控制台放行3306端口。

坑4:密码不对

报错不是"连接不上",而是"Access denied"。

原因: 密码错了。

解决: 确认密码,注意大小写。

总结

远程连接失败排查顺序:

  1. 先授权远程用户
  2. 再开防火墙3306
  3. 然后改bind-address
  4. 最后查云安全组

记住: 90%的情况都是没授权或者防火墙没开。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:45 

MySQL修改root密码,多种方法汇总

前言

知道旧密码,想改个新密码,有好几种方法。本文汇总常用的改密码方法。

方法一:ALTER USER(推荐)

登录MySQL后:

ALTER USER 'root'@'localhost' IDENTIFIED BY '你的新密码';

然后刷新:

FLUSH PRIVILEGES;

优点: 官方推荐,语法标准,MySQL 5.7/8.0都支持。

方法二:SET PASSWORD

SET PASSWORD FOR 'root'@'localhost' = PASSWORD('你的新密码');

刷新:

FLUSH PRIVILEGES;

注意: MySQL 8.0以后 PASSWORD() 函数被删了,不能用了。

方法三:UPDATE直接改

UPDATE mysql.user SET authentication_string=PASSWORD('你的新密码') 
WHERE User='root' AND Host='localhost';

刷新:

FLUSH PRIVILEGES;

注意: 同样,MySQL 8.0不能用PASSWORD()函数。

方法四:命令行修改

不用登录MySQL,直接命令行:

mysqladmin -u root -p password "你的新密码"

输入旧密码后,就改成新密码了。

MySQL 8.0改密码

MySQL 8.0改密码语法有变化:

方法一:ALTER USER(推荐)

ALTER USER 'root'@'localhost' IDENTIFIED BY '你的新密码';

方法二:SET PASSWORD

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的新密码';

不同Host的root用户

root可能有多个:

SELECT user, host FROM mysql.user WHERE user='root';

输出可能是:

user host
root localhost
root 127.0.0.1
root %

每个host的root密码是独立的,要分别改。

ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
ALTER USER 'root'@'127.0.0.1' IDENTIFIED BY '新密码';
ALTER USER 'root'@'%' IDENTIFIED BY '新密码';

常见坑

坑1:改了密码还是旧密码能登

原因: 没执行 FLUSH PRIVILEGES;

解决: 改完密码一定要刷新权限。

坑2:MySQL 8.0报语法错误

ERROR 1064 (42000): You have an error in your SQL syntax

原因: 用了 PASSWORD() 函数,MySQL 8.0删了。

解决: 用 ALTER USER 语句。

坑3:改了密码远程登不上

本地能登,远程连不上。

原因: 只改了localhost的密码,远程用户的密码没改。

解决: 把所有host的root密码都改了。

坑4:密码太简单报错

ERROR 1819 (HY000): Your password does not satisfy the current policy requirements

原因: MySQL密码强度校验太严。

解决: 用复杂点的密码(大小写+数字+特殊字符),或者关掉密码校验:

SET GLOBAL validate_password_policy=LOW;

坑5:改完密码phpStudy/phpMyAdmin连不上

原因: 站点配置文件里的密码还是旧的。

解决: 改项目配置文件里的数据库密码。

总结

知道旧密码改密码:

方法 适用版本 推荐度
ALTER USER 5.7/8.0 推荐
SET PASSWORD 5.7及以前 一般
UPDATE mysql.user 5.7及以前 不推荐
mysqladmin 所有版本 一般

记住: 改完密码一定要 FLUSH PRIVILEGES;

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:44 

MySQL查看当前连接数,show processlist

前言

MySQL连接数太多,报"Too many connections",怎么看当前有多少连接?哪些连接在跑什么SQL?用show processlist。

一、查看当前连接

基本命令

SHOW PROCESSLIST;

输出:

Id User Host db Command Time State Info
123 root localhost:54321 mydb Query 0 starting SHOW PROCESSLIST
124 www 192.168.1.100:1234 mydb Sleep 30 NULL

每列含义:

  • Id:连接ID,kill的时候用
  • User:用户名
  • Host:客户端IP和端口
  • db:当前数据库
  • Command:当前命令(Query/Sleep/Connect)
  • Time:当前状态持续时间(秒)
  • State:状态
  • Info:正在执行的SQL

显示完整SQL

SHOW FULL PROCESSLIST;

默认Info列只显示前100个字符,加FULL显示完整SQL。

二、查看连接数

当前连接数

SHOW STATUS LIKE 'Threads_connected';

最大连接数

SHOW VARIABLES LIKE 'max_connections';

历史最大连接数

SHOW STATUS LIKE 'Max_used_connections';

三、杀掉连接

杀掉某个连接

KILL 连接ID;

比如杀掉ID为123的连接:

KILL 123;

杀掉所有Sleep连接

-- 先查出来
SELECT CONCAT('KILL ', id, ';') FROM information_schema.processlist 
WHERE user = 'www' AND command = 'Sleep';

把结果复制出来执行,就能批量杀掉。

四、常用查询

按用户统计连接数

SELECT user, COUNT(*) FROM information_schema.processlist 
GROUP BY user;

按IP统计连接数

SELECT SUBSTRING_INDEX(host, ':', 1) AS ip, COUNT(*) 
FROM information_schema.processlist 
GROUP BY ip;

查看执行超过10秒的SQL

SELECT * FROM information_schema.processlist 
WHERE time > 10;

五、调整最大连接数

临时调整

SET GLOBAL max_connections = 1000;

永久调整

改my.cnf:

[mysqld]
max_connections = 1000

重启MySQL生效。

常见坑

坑1:Sleep连接太多

大量Sleep连接占着连接数,导致新连接进不来。

原因: 程序没关连接,连接池没配好。

解决:

  1. 调小 wait_timeout,让空闲连接自动断开
  2. 检查程序连接池配置
SET GLOBAL wait_timeout = 60;

坑2:看不到其他用户的连接

普通用户只能看到自己的连接。

解决: 用root用户登录,或者PROCESS权限。

坑3:kill了连接还在

kill了连接,但连接还在列表里。

原因: 连接正在回滚,需要等一会。

解决: 等几秒再看,或者重启MySQL。

坑4:连接数突然暴涨

突然一堆连接进来,数据库卡死。

原因: 可能是程序bug,或者被攻击了。

排查: 按IP统计,看哪个IP连接最多。

总结

常用命令:

命令 作用
SHOW PROCESSLIST 看当前连接
SHOW FULL PROCESSLIST 看完整SQL
SHOW STATUS LIKE 'Threads_connected' 看当前连接数
KILL 连接ID 杀掉连接

记住: 连接数满了先看processlist,找出是谁占着连接。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:43 
'); })();