报错根本原因不是函数语法错误,而是MySQL开启binlog后强制要求函数必须声明DETERMINISTIC、NO SQL或READS SQL DATA三者之一,否则拒绝创建;临时解决用SET GLOBAL log_bin_trust_function_creators = 1,永久方案是修改my.cnf并重启。

直接说结论:这个报错不是函数写错了,而是 MySQL 在开启 binlog 的前提下,强制要求你明确声明函数的数据访问行为。不加声明,就拒绝创建。
为什么必须加 DETERMINISTIC、NO SQL 或 READS SQL DATA
MySQL 开启 binlog(比如用于主从复制或 PITR)后,为保证主从一致性,不允许“黑盒式”函数——即无法判断它是否安全地参与复制。所以你必须在 CREATE FUNCTION 语句里,用且仅用以下三者之一标注:
-
DETERMINISTIC:输出完全由输入参数决定(如ABS()、CONCAT()),不能含RAND()、NOW()、子查询等非确定性操作 -
NO SQL:函数体内一句 SQL 都不执行(纯计算或字符串处理) -
READS SQL DATA:只执行SELECT,不修改任何数据
注意:MODIFIES SQL DATA 和 CONTAINS SQL 在函数中不被接受——它们只适用于存储过程或触发器。
临时绕过:set global log_bin_trust_function_creators=1
这条命令能立刻让 MySQL 放宽检查,允许不带声明的函数创建成功:
SET GLOBAL log_bin_trust_function_creators = 1;
但它只对当前会话生效,MySQL 重启后失效。更重要的是:
- 如果用在主从环境中,从库也必须执行这句,否则导入或同步时仍会报错
ERROR 1418 - 它降低安全性:任何用户(哪怕没 SUPER 权限)都能创建可能破坏复制一致性的函数
- 部分托管数据库(如阿里云 RDS、AWS RDS)禁止该变量修改,这条路根本走不通
正确写法示例:声明必须紧接 RETURNS 后面
声明位置很关键——必须放在返回类型之后、BEGIN 之前,且只能选一个。常见错误是漏掉、放错位置,或写多个:
CREATE FUNCTION add_tax(price DECIMAL(10,2)) RETURNS DECIMAL(10,2) DETERMINISTIC BEGIN RETURN price * 1.1; END
如果你的函数查表:
CREATE FUNCTION get_user_name(uid INT) RETURNS VARCHAR(50) READS SQL DATA BEGIN DECLARE name VARCHAR(50); SELECT username INTO name FROM users WHERE id = uid; RETURN name; END
如果函数只做字符串拼接、日期计算、数学运算,且不含任何 SQL,就用 NO SQL。
永久生效:改配置文件比 set global 更可靠
编辑 /etc/my.cnf(Linux)或 my.ini(Windows),在 [mysqld] 段下添加:
log_bin_trust_function_creators = 1
然后重启 MySQL。但要注意:
- 所有参与复制的节点(主+从)都得同步改,否则从库同步时仍卡住
- 某些云厂商控制台提供“参数模板”,需在模板里修改并应用到实例,而非直接改文件
- 即使开了这个开关,仍建议给函数加上正确声明——这是可读性、可维护性和主从安全的底线
真正容易被忽略的点是:声明不是“可选装饰”,而是 binlog 环境下的契约。哪怕你只是本地开发,只要 mysqld 启用了 binlog(默认很多发行版已开),就得守这个规则。


















