应优先查占用进程再决策:Linux用sudo lsof -i :3306或sudo netstat -tuln | grep :3306确认是否真被占,若为mysqld则可能是旧实例残留,若为docker-proxy、java等需评估是否可停;不可停时才修改my.cnf中[mysqld]段port=3307并重启服务。

查端口占用:先确认是不是3306真被占了
MySQL 启动时出现 Address already in use,绝大多数情况就是 3306 端口被别的进程绑定了。别急着改配置或删文件,先验证是不是真冲突。
执行这两条命令之一:
-
sudo lsof -i :3306(推荐,更直观) sudo netstat -tuln | grep :3306
如果输出里有 mysqld,说明是旧实例没退出干净;如果是 docker-proxy、java、node 或其他进程,就得判断要不要杀——Docker 容器里的 MySQL 实例、本地开发的另一个 MySQL 服务、甚至某个 Spring Boot 项目嵌入的 H2/MySQL 测试库,都可能悄摸占着端口。
杀还是不杀:看进程类型再决定
不是所有占着 3306 的进程都该 kill -9。盲目杀错可能影响线上容器或协作服务。
- 如果是残留的
mysqld进程(比如上次崩溃没退出),用ps aux | grep mysqld确认 PID,再sudo kill -9 <PID> - 如果是 Docker 容器:
docker ps | grep 3306查容器名,用docker stop <container_name>更安全 - 如果是其他服务(如测试用的
mysql-server包、Laravel Valet、MAMP),确认是否需要保留;不需要就停服务,需要就换 MySQL 端口
特别注意:systemctl status mysqld 显示 “active (exited)” 并不代表 MySQL 在跑——它只是启动脚本执行完了,实际守护进程根本没起来,这时候日志里八成也是 Address already in use。
改端口 or 改服务:两个务实选择
不想动现有服务?那就让新 MySQL 让路。修改 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf 的 [mysqld] 段:
port = 3307
改完必须重启前验证配置语法:
- MySQL 5.7.16+:
mysqld --defaults-file=/etc/my.cnf --validate-config - 老版本:
mysqld --defaults-file=/etc/my.cnf --verbose --help | head -20看有没有报错
改端口后,客户端连接也要同步更新:mysql -P 3307 -u root -p,别漏掉 -P(大写 P);应用配置里的 jdbc:mysql://localhost:3306 也得改成 :3307。
容易被忽略的细节:socket 文件和 SELinux
有时候明明端口空着,还报 Address already in use,可能是 socket 文件残留或 SELinux 拦截。
- 检查
/var/run/mysqld/mysqld.sock是否存在且属主是mysql用户;若存在但 mysqld 没跑,手动删掉再试(sudo rm /var/run/mysqld/mysqld.sock) - RHEL/CentOS 上开启 SELinux 时,
mysqld可能被禁止绑定网络端口,临时关 SELinux 测试:sudo setenforce 0;若恢复启动,需加策略:sudo setsebool -P mysqld_can_network_connect 1 - 某些云主机或容器环境会限制非特权端口范围,
3306被系统级防火墙拦截,需检查firewalld或iptables规则
最麻烦的情况是多个 MySQL 实例共存又没做实例隔离(比如没配 socket 路径或 pid-file),这种环境下 Address already in use 往往是表象,根因是进程间资源争抢,得靠 datadir 分离 + 独立配置文件 + systemd 实例模板来解。


















