inet_aton和inet_ntoa仅支持ipv4,需用int unsigned存储、cast转无符号、配合正则校验;ipv6须用inet6_aton/inet6_ntoa配合varbinary(16),不可混用。

MySQL 里用 INET_ATON 和 INET_NTOA 转 IP 和整数,能用,但得小心 IPv4 边界和 NULL 行为——尤其别在生产环境直接存 INET_ATON('255.255.255.255') 结果当无符号整数处理。
为什么 INET_ATON 返回的是有符号整数?
MySQL 的 INET_ATON 把 IPv4 地址转成 BIGINT SIGNED,比如 INET_ATON('192.168.1.1') 得到 3232235777,但它在 MySQL 内部按有符号数存,所以 '255.255.255.255' 会变成 -1(因为 4294967295 超出 BIGINT SIGNED 正数上限 263−1,但实际是按 32 位无符号解释后被截断/补码显示)。
- 真正存储时建议用
UNSIGNED INT字段类型,而不是依赖函数返回值的符号性 -
SELECT INET_ATON('255.255.255.255');在多数 MySQL 版本返回-1,不是4294967295 - 如果字段定义为
INT UNSIGNED,插入INET_ATON('255.255.255.255')会报错或截断,取决于 SQL 模式
怎么安全地把 IP 存进 INT UNSIGNED 字段?
别直接 INSERT INTO t(ip_int) VALUES(INET_ATON('...'))——它可能溢出或变负。应该显式转无符号语义:
INSERT INTO t(ip_int)
VALUES(CAST(INET_ATON('192.168.1.1') AS UNSIGNED));
-
CAST(... AS UNSIGNED)强制按 32 位无符号解释,'255.255.255.255'就真变成4294967295 - 字段类型必须是
INT UNSIGNED,否则 CAST 后仍可能被拒绝(如严格模式下超出SIGNED INT范围) - 注意:MySQL 8.0.19+ 支持
INET6_ATON处理 IPv6,但INET_ATON仅限 IPv4,传 IPv6 地址会返回NULL
INET_NTOA 遇到非合法整数会怎样?
INET_NTOA 对输入非常脆弱:只要不是有效的 32 位无符号整数值(即不在 0~4294967295),就返回 NULL。
-
SELECT INET_NTOA(-1);→NULL(哪怕你知道它对应'255.255.255.255') -
SELECT INET_NTOA(4294967296);→NULL(超上限) - 常见坑:从
INT字段读出负数再喂给INET_NTOA,结果全NULL,查半天才发现字段没设UNSIGNED - 调试时可用
SELECT ip_int, INET_NTOA(CAST(ip_int AS UNSIGNED)) FROM t;绕过符号问题
IPv6 怎么办?别硬套 INET_ATON
INET_ATON/INET_NTOA 完全不支持 IPv6。MySQL 5.6.3+ 提供了 INET6_ATON 和 INET6_NTOA,它们返回 VARBINARY(16),不是整数:
SELECT INET6_ATON('::1'); -- 返回 0x00000000000000000000000000000001
SELECT INET6_NTOA(0x00000000000000000000000000000001); -- 返回 '::1'
- 不能用普通整数字段存
INET6_ATON结果,必须用BINARY(16)或VARBINARY(16) - 索引效率比 IPv4 整数方案低,WHERE 中用
INET6_NTOA会无法走索引 - 如果业务同时要兼容 IPv4/IPv6,别试图统一成整数——类型语义已分裂,老实用两个字段或一个
VARBINARY(16)加标记字段
真正麻烦的不是函数怎么写,而是字段类型、CAST 时机、NULL 处理这三处——漏掉任意一个,查询结果就突然变空或者翻车成负数。











