sql_require_primary_key仅在DDL阶段强制主键定义,不影响DML操作;它不拦截无主键表的查询或写入,也不干预执行计划,仅防止CREATE/ALTER时缺失主键报错ERROR 3750。

不能通过配置“强制执行主键约束”来防止无主键表被查询或写入——MySQL 没有运行时级别的“主键执行约束”,只有建表/改表时的 DDL 强制开关 sql_require_primary_key。
sql_require_primary_key 只在 CREATE / ALTER 表时起作用
这个参数不是“执行约束”,而是“结构定义约束”:它只拦截 DDL 语句,不干预任何 DML(SELECT、INSERT、UPDATE、DELETE)行为。
- 设为
ON后,CREATE TABLE t(id INT)会直接报错:ERROR 3750 (HY000): Unable to create or change a table without a primary key - 但已有无主键表(比如老系统遗留的 MyISAM 表),照样能
SELECT * FROM t或INSERT INTO t VALUES (1) -
ALTER TABLE t ADD PRIMARY KEY (id)仍可执行,哪怕数据里有重复值或 NULL —— 此时会失败,但失败原因是数据违反主键语义,不是参数本身在“执行约束”
为什么你不能靠它拦住无主键表的 DML 操作
MySQL 的存储引擎(InnoDB / MyISAM)本身不要求主键存在才能读写数据。InnoDB 即使没显式主键,也会悄悄生成一个隐藏的 ROW_ID;MyISAM 根本不依赖主键做行定位。
-
sql_require_primary_key = ON不会让INSERT拒绝无主键表的数据写入 - 也不会让
SELECT报错或自动重写成带主键条件的语句 - 更不会在事务提交时校验“这一行有没有对应主键值”——那是应用层或触发器的事
真正想防无主键表,得靠流程和权限控制
参数只是第一道门,拦不住已存在的表,也拦不住绕过它的操作路径。
- DBA 应在部署阶段用脚本扫描
information_schema.TABLES,查TABLE_SCHEMA NOT IN ('mysql','sys') AND ENGINE='InnoDB' AND TABLE_ROWS > 0 AND TABLE_NAME NOT IN (SELECT TABLE_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE CONSTRAINT_NAME='PRIMARY') - 禁止普通账号使用
CREATE TABLE权限,只开放给带模板校验的 DB 工具或 ORM 迁移命令 - 在 CI/CD 流程中加入 SQL 审计规则,拒绝提交不含
PRIMARY KEY的CREATE TABLE语句 - 注意:
sql_require_primary_key在 MySQL 8.0.19+ 才有,且默认是OFF;升级后不显式开启就等于没开
最容易被忽略的一点:即使开了 sql_require_primary_key,只要用户有 ALTER TABLE 权限,就能对已有无主键表执行 DROP PRIMARY KEY(如果它本来就有),或者先加再删——参数管不了“删主键”,只管“建/改时没主键”。


















