INET_ATON仅支持IPv4,IPv6需用INET6_ATON;传入非法格式或IPv6静默返回0,非报错;存IPv4须用INT UNSIGNED,IPv6须用VARBINARY(16);混合场景推荐统一用INET6_*函数。

MySQL里用INET_ATON转IP字符串为整数,但IPv6不支持
直接说结论:INET_ATON只处理IPv4,输入"192.168.1.1"返回整数3232235777;传入IPv6(如"::1")或非法格式(如"256.1.1.1")会静默返回0,不是报错——这是最容易踩的坑。
常见错误现象:WHERE条件里写WHERE ip_int = INET_ATON('192.168.1.1'),结果查不到数据,其实是因为字段里存的是IPv6,或者原始IP有空格/换行没trim。
- 必须提前清洗输入:
TRIM(BOTH FROM ' 192.168.1.1 ') - IPv4地址段超界(如
"256.0.0.0")也返回0,建议加校验:INSTR('192.168.1.1', ':') = 0先排除IPv6 -
INET_ATON返回的是无符号32位整数,存进数据库时字段类型得是INT UNSIGNED,否则高位溢出变负数
用INET_NTOA把整数转回IPv4字符串,别在SELECT里盲目套用
INET_NTOA是INET_ATON的逆操作,但只认32位无符号整数值。传入负数、NULL或超出范围的数(比如4294967296),结果是NULL,不会报错也不会提示。
典型误用场景:日志表里IP存的是BIGINT,为了兼容IPv6后来改用INET6_ATON,但旧SQL还留着INET_NTOA(ip_int),一执行就大片NULL。
- 确认源字段确实是IPv4转换来的整数,且类型为
INT UNSIGNED - 如果字段可能混IPv6,先判断:
CASE WHEN ip_int > 0 THEN INET_NTOA(ip_int) ELSE NULL END - 不要在ORDER BY里用
INET_NTOA做排序——函数计算开销大,且无法走索引
IPv6必须换INET6_ATON和INET6_NTOA,它们返回的是二进制值
INET6_ATON返回VARBINARY(16),不是整数。这意味着你不能用=直接比大小,也不能塞进INT字段里存——这是和IPv4函数最根本的区别。
常见错误:把INET6_ATON('::1')结果插入CHAR(39)字段,看起来像"00000000000000000000000000000001",其实是乱码,因为二进制被当字符串转义了。
- 存IPv6必须用
VARBINARY(16)字段类型 - 比较用
=即可:WHERE ip_bin = INET6_ATON('2001:db8::1') - 想看可读形式,SELECT里用
INET6_NTOA(ip_bin),但别在WHERE里用它做条件——没法走索引 - 注意:MySQL 5.6.3+才支持,低版本只能靠字符串存储或第三方函数
混合IPv4/IPv6场景下,统一用INET6_*函数更稳妥
哪怕当前全是IPv4,只要未来可能接入IPv6,就别碰INET_ATON/INET_NTOA。因为INET6_ATON对IPv4也兼容,会自动补前导零转成16字节二进制,而INET_ATON对IPv6完全无能为力。
性能影响很小,但类型安全高得多。唯一代价是存储空间从4字节涨到16字节,对绝大多数业务不是瓶颈。
- 存IPv4时:
INET6_ATON('192.168.1.1')→00000000000000000000FFFFC0A80101(16字节) - 查IPv4仍可用
INET6_NTOA还原,输出还是"192.168.1.1" - 应用层无需区分协议,数据库字段类型和SQL写法完全一致
真正麻烦的是历史数据迁移:老表用INT存IPv4,新逻辑用VARBINARY(16),中间没有自动转换桥接。这点得在改表前就想清楚,别等上线才发现WHERE里混用两个函数导致结果错乱。










