MySQL varchar(255) 能存多少个汉字?utf8mb4 下的字符、字节和各项上限

30 十月,2026 • 指南 • 44次浏览 • 1 分钟 阅读

书桌上的笔记本电脑屏幕显示抽象的数据库表格网格,旁边摊开一本画着表格草图的笔记本

在 MySQL 8.4 中,VARCHAR(N) 的 N 是字符数,utf8mb4 下 VARCHAR(255) 能存 255 个汉字。本文依据官方文档,讲清每个字符占几个字节、长度前缀、65535 字节行上限、16383 字符上限和索引 191 的由来,并给出测量 SQL 与长度建议。

在 MySQL 8.4 中,VARCHAR(N) 的 N 是字符数,不是字节数,所以 utf8mb4 下的 VARCHAR(255) 能存 255 个汉字,换成 255 个英文字母或 255 个 😀 这样的单码位表情符号也一样。准确地说,N 计的是 Unicode 码位,有些表情符号由多个码位组成,看起来是一个,却会算成多个字符。按文档规则推算,这一列的数据最坏情况下占 255 × 4 = 1020 字节,再加 2 字节长度前缀,最多 1022 字节。

以下依据 MySQL 8.4 官方文档,2026 年 10 月 29 日查阅。我们没有在自己的 MySQL 上实测,文中标“推算”的数字是按文档规则算出来的,既不是文档原文,也不是测试结果。更早的 MySQL 版本规则可能不同,本文不展开。

VARCHAR(N) 的 N 是字符数还是字节数

N 是字符数。MySQL 8.4 的 CHAR 和 VARCHAR 类型文档写得很明确,声明的长度表示你想存储的最大字符数,并举例说 CHAR(30) 最多能存 30 个字符。VARCHAR 遵循同一条规则。

放到实际建表里,你写 VARCHAR(255),MySQL 就按 255 个字符限制长度。汉字比字母占的字节多,但并不会因此少存几个字。一个昵称字段可以写满 255 个汉字,也可以写满 255 个字母,两者在磁盘上占的空间不同,能存的个数却一样。

容易让人混淆的是另外几个数字。文档允许 VARCHAR 声明的长度在 0 到 65535 之间,同时又说明,实际可用的最大长度受两方面约束,一是所有列共享的 65535 字节行大小,二是这一列使用的字符集。也就是说,N 本身按字符计,真正限制字段容量的几个因素却都按字节计。后面要讲的长度前缀、整行大小和索引长度,单位都是字节。

把这两层分开来看,大部分疑问就清楚了。业务上问“能放几个字”,看 N 就够了。超过 N 时,按 CHAR 和 VARCHAR 文档,未开启严格 SQL 模式时值会被截断并产生警告,开启严格模式时不会写入并报错,所以应用层最好先校验长度;排查建表报错或索引报错时,要看字符集里每个字符最多占几个字节,再乘以 N。

utf8mb4 和 utf8mb3 下一个字符占多少字节

utf8mb4 每个字符最多占 4 字节,utf8mb3 最多 3 字节,常用汉字在两者中都占 3 字节。这两个上限写在 MySQL 8.4 存储需求文档里。utf8mb4 字符集文档还说明,utf8mb4 同时支持基本多文种平面(BMP)和增补平面的字符,utf8mb3 只支持 BMP。BMP 字符在两种字符集下的存储方式相同;增补平面的字符,比如表情符号和“𠮷”这类生僻字,utf8mb3 根本存不进去。

下表按 UTF-8 编码计算字节数,utf8mb4 列里保存的正是这样的 UTF-8 字节。

内容字符数utf8mb4 字节utf8mb3
abc333
海豚266
你好,世界!61818
😀14无法存储
𠮷14无法存储

从表里能看出几点。英文字母和数字每个 1 字节,常用汉字每个 3 字节。中文的全角逗号和感叹号同样是 3 字节,所以“你好,世界!”这六个字符正好是 18 字节。😀 这样的单码位表情符号和 𠮷 这样的增补平面汉字每个码位 4 字节,这一档正是 utf8mb4 比 utf8mb3 多出来的部分。由多个码位组成的表情符号,整个占的字节会超过 4。

对 VARCHAR 来说,真正要紧的是“最多”二字。长度前缀的规则看的是值可能需要多少字节,单列上限 16383 也正好对应每字符 4 字节(推算),所以一列 utf8mb4 的 VARCHAR(255) 即使平时只存汉字,计算上限时仍要按每个字符 4 字节估算。至于一个汉字为什么在 UTF-8 里占 3 字节、在 GBK 里又占多少,可以参阅一个汉字占几个字节,这里不再重复。

VARCHAR 的长度前缀什么时候是 1 字节,什么时候是 2 字节

列里的值可能超过 255 字节时,长度前缀是 2 字节,否则是 1 字节。按照文档的说明,VARCHAR 的值以“长度前缀加数据”的形式存储,前缀记录数据的字节数。存储需求页面把它写成了公式,值需要 0 到 255 字节时占 L + 1 字节,可能超过 255 字节时占 L + 2 字节,其中 L 是该值实际的字节长度。

关键在“可能”二字。前缀占几个字节,取决于这一列最多可能存多少字节,与某一行实际存了什么关系不大。utf8mb4 每个字符最多 4 字节,按文档规则推算,VARCHAR(63) 最坏情况是 252 字节,仍在 255 以内,用 1 字节前缀;VARCHAR(64) 最坏情况是 256 字节,超过了 255,就要用 2 字节前缀。因此在 utf8mb4 下,从 VARCHAR(64) 起,长度前缀都是 2 字节(推算)。

以一列 utf8mb4 的 VARCHAR(255) 为例,下面几个具体值都是按文档公式推算的。

  • 存 255 个常用汉字,数据 765 字节,加 2 字节前缀,共 767 字节。
  • 存 255 个 😀 这样的单码位表情符号,数据 1020 字节,加 2 字节前缀,共 1022 字节,这是这一列的最坏情况。
  • 只存“abc”,数据 3 字节,按通用公式前缀仍是 2 字节,共 5 字节。这是数据类型层面的计算,InnoDB 实际的物理占用还与行格式有关。

常有人问,为什么大家习惯写 255 而不是 256。按同样的规则推算,在每个字符最多占 1 字节的字符集里,VARCHAR(255) 恰好是能用 1 字节前缀的最大长度,写成 VARCHAR(256) 就需要 2 字节。到了 utf8mb4,这条分界线在 64 个字符时就已越过,VARCHAR(255) 和 VARCHAR(256) 用的都是 2 字节前缀。这里只讨论前缀规则,不涉及两者的性能差异。

VARCHAR 最大长度是 65535 吗

不完全是。65535 既是 VARCHAR 声明长度的上限,也是一整行所有列合计的字节上限;具体到一列 utf8mb4 的 VARCHAR,文档给出的最大值是 16383 个字符。

行大小的限制写在 InnoDB 限制文档里,MySQL 本身规定一行中所有列的合计大小不能超过 65535 字节。CHAR 和 VARCHAR 的文档也特别强调,这 65535 字节由所有列共享。存储需求文档则直接写明,使用 utf8mb4 的 VARCHAR 列最多可以声明为 16383 个字符。

16383 这个数可以这样理解(推算)。16383 × 4 = 65532 字节,加上 2 字节长度前缀是 65534 字节,刚好在 65535 以内;如果写成 16384,最坏情况就会超出。这是单列独占一整行时的理论上限,表里只要还有其他列,留给这一列的空间就更少。

问题往往出在“同一张表里放了好几个大 VARCHAR”。按文档规则推算,两列 utf8mb4 的 VARCHAR(16383) 最坏情况下各需 65532 字节数据,合计远超 65535,不可能放进同一行。实际项目里用不着这么极端,四列 utf8mb4 的 VARCHAR(5000) 最坏就要 4 × 20002 = 80008 字节(推算),同样超出上限。这类表定义会因超过行大小上限而导致建表或改表失败。MySQL 8.4 的列数和行大小限制文档里,这类示例的报错编号是 ERROR 1118,信息以 Row size too large 开头。

遇到这种情况,可以从两方面着手。一是重新核对每一列的真实需求,把明显偏大的 N 调小,下一节会讲怎样用 SQL 查看现有数据到底有多长。二是把篇幅很长的正文类内容改用 TEXT 类型。同一份文档写明,TEXT 和 BLOB 列的内容与行的其余部分分开存储,计算 65535 字节行上限时只占 9 到 12 字节。InnoDB 实际把数据放在页内还是页外,还取决于行格式和内容长度。另外,InnoDB 自己还有页内行大小限制,默认 16KB 页时略小于半页,排查 Row size too large 时也要考虑。TEXT 的长度上限请以存储需求文档为准,本文不展开。

utf8mb4 的索引为什么常见 191 个字符

191 来自旧行格式下 767 字节的索引前缀上限。767 ÷ 4 = 191.75,所以按文档规则推算,utf8mb4 列最多 191 个字符能完整放进这样的索引。InnoDB 限制文档也明确举了这个例子,在 utf8mb4、每字符最多 4 字节的前提下,超过 191 个字符的列前缀索引就会碰到这个上限。

InnoDB 限制文档的原文规定是,使用 DYNAMIC 或 COMPRESSED 行格式的 InnoDB 表,索引键前缀长度上限为 3072 字节;使用 REDUNDANT 或 COMPACT 行格式的表,上限为 767 字节。和行大小一样,这里的单位也是字节,而 utf8mb4 要按每字符 4 字节估算。

按这两个数字推算,不同行格式下的结论相差很大。

  • REDUNDANT 或 COMPACT 行格式,上限 767 字节,utf8mb4 列最多 191 个字符能完整建索引。
  • DYNAMIC 或 COMPRESSED 行格式,在默认 16KB 页大小下上限 3072 字节,3072 ÷ 4 = 768,utf8mb4 列最多 768 个字符能完整建索引。一列 VARCHAR(255) 最坏 1020 字节,完全放得下。

同一文档还写明,如果建实例时把 innodb_page_size 设为 8KB 或 4KB,索引键长度上限会按比例降到 1536 字节和 768 字节。在 4KB 页上,utf8mb4 的 VARCHAR(255) 最坏 1020 字节就超过了上限。复合索引还要看各列合计的长度。

再做一个对照,191 的来历就更清楚了(推算)。utf8mb3 每字符最多 3 字节,VARCHAR(255) 最坏是 765 字节,正好在 767 字节以内;同一列换成 utf8mb4,最坏变成 1020 字节,在 767 字节的上限下就放不下了,于是需要建索引的列被改成了 191。

所以看到别人的建表语句里写着 VARCHAR(191),不必照搬。先弄清自己的表用的是哪种行格式,再按对应的字节上限换算。如果是 DYNAMIC 或 COMPRESSED 并使用默认 16KB 页,191 这个限制就不适用,真正需要留意的是超过 768 个字符的列,比如很长的网址;页大小为 8KB 或 4KB 时上限更低。

utf8mb4 下 VARCHAR 的几道上限对照

utf8mb4 下的 VARCHAR 同时受字符数、长度前缀、单列上限、整行大小和索引长度五条规则约束。下表把它们汇总在一起,标“推算”的是按文档规则算出的结果。

限制文档规定utf8mb4 下的含义
列长度 N字符数,0 到 65535VARCHAR(255) 可以存 255 个字符
长度前缀值可能超过 255 字节时用 2 字节,否则用 1 字节从 VARCHAR(64) 起最坏情况达到 256 字节,因此用 2 字节(推算)
单列最大utf8mb4 的 VARCHAR 最多 16383 字符文档原文,最坏 65532 字节数据加 2 字节前缀(推算)
整行所有列合计 65535 字节两列 VARCHAR(16383) 放不进同一行,2 × 65532 已远超上限(推算)
索引前缀DYNAMIC/COMPRESSED 3072 字节(默认 16KB 页;8KB 页 1536,4KB 页 768),REDUNDANT/COMPACT 767 字节16KB 页下分别最多 768 个字符和 191 个字符(推算)

排查问题时可以对照这张表。想知道能存几个字,看第一行;建表时报行太大,看第四行;建索引失败,看最后一行。

utf8 和 utf8mb4 应该选哪个

新项目应该选 utf8mb4。MySQL 8.4 的 utf8mb3 字符集文档说明,MySQL 过去把 utf8 用作 utf8mb3 的别名,这种用法现已弃用;在 MySQL 8.4 中,SHOW 语句和 INFORMATION_SCHEMA 表的列里显示的是 utf8mb3,而不再是 utf8。

utf8mb3 本身也已弃用。文档写明,它在 8.0.x 和 8.4.x 这两个 LTS 系列中仍受支持,但预计会在未来的某个大版本中移除,并明确指出所有新应用都应使用 utf8mb4。另外,服务器字符集文档给出的 8.4 服务器默认字符集和排序规则是 utf8mb4 和 utf8mb4_0900_ai_ci。

这对字段长度有两方面影响。一是能存什么,utf8mb3 存不了表情符号和增补平面的汉字,用户昵称、评论这类内容迟早会遇到。二是字节估算,同样一列 VARCHAR(255),在 utf8mb3 下最坏 765 字节,在 utf8mb4 下最坏 1020 字节(推算)。从 utf8mb3 换到 utf8mb4 时,原本刚好放得下的行大小或索引长度可能就会超限,修改前最好按上一节的表重新算一遍。

如果你在老项目的表结构里看到 utf8mb3,说明这张表或这一列用的是 utf8mb3,也可能是当年写成 utf8 建的。如何迁移到 utf8mb4 不在本文讨论范围内,具体步骤请以上面链接的官方文档为准。

怎样用 SQL 测量现有数据的字符数和字节数

用 CHAR_LENGTH() 查字符数,用 LENGTH() 查字节数。MySQL 8.4 的字符串函数文档说明,LENGTH() 返回字节数,CHAR_LENGTH() 返回字符(码位)数。文档示例中的“海豚”两个字,LENGTH 是 6,CHAR_LENGTH 是 2。

如果想调整已有表的字段长度,可以按下面的顺序检查。表名 posts 和列名 title 只是示例,请换成你自己的。这几条语句我们没有在自己的环境里执行过,结果以你的 MySQL 为准。

  1. 先确认字符集。执行 SHOW CREATE TABLE posts; 然后在输出的建表语句里找到 title 这一列和表定义的末尾,看用的是 utf8mb4 还是 utf8mb3。
  2. 再查现有数据的最大长度。执行 SELECT MAX(CHAR_LENGTH(title)) AS max_chars, MAX(LENGTH(title)) AS max_bytes FROM posts; 第一个结果是最长的值有多少个字符,第二个是占字节最多的值有多少字节。
  3. 把结果和列定义对比。max_chars 决定 N 至少要设多大,max_bytes 帮你判断实际内容离字节上限还有多远。

要注意,max_chars 和 max_bytes 是分别统计的最大值,可能来自不同的记录,所以不能用两者的比值判断最长标题由什么字符组成。想看某一条记录,可以同时查它自己的两个值,例如 SELECT title, CHAR_LENGTH(title) AS chars, LENGTH(title) AS bytes FROM posts ORDER BY CHAR_LENGTH(title) DESC LIMIT 1; 在 utf8mb4 下,如果某条记录的字节数超过码位数的 3 倍,说明其中至少有一个 4 字节字符;没有超过,也不能排除。

也可以单独验证函数本身。在连接字符集为 utf8mb4 时执行 SELECT LENGTH('海豚'), CHAR_LENGTH('海豚'); 按文档示例应得到 6 和 2。在 utf8mb4 列里,LENGTH() 返回的就是值的 UTF-8 字节数。

中文字段的 VARCHAR 长度怎么选

先按业务需求确定字符数上限,再用字节规则检查索引和行大小。下表是常见字段的参考范围,这些数字只是建议,不是规则,最终以你的业务和实际数据为准。

用途建议长度注意事项
姓名、用户名VARCHAR(50) 到 VARCHAR(100)昵称可能含表情符号,要用 utf8mb4
文章或商品标题VARCHAR(100) 到 VARCHAR(255)DYNAMIC 行格式下 VARCHAR(255) 可以完整建索引(推算)
网址 URLVARCHAR(2048)超过 768 个字符,utf8mb4 在 DYNAMIC 行格式下无法完整建索引(推算)
长正文、详细描述TEXT不必占用很长的 VARCHAR,避免整行超限

确定长度前,不妨先问自己几个问题。这一列要不要建索引?如果要,N 乘以 4 不能超过所用行格式的索引字节上限。表里有几列大 VARCHAR?把它们的最坏字节数相加,再算上其他列,看离 65535 还有多少余地。现有数据最长有多少?用上一节的 SQL 查一下,在此基础上留出余量,比凭感觉一律写 255 更稳妥。

如果一个字段写到几千个字符还担心不够用,通常说明它更像正文而不是短文本,这时改用 TEXT 比继续加大 N 更合适。

不写代码怎样估算一段中文占多少字节

把文本粘贴到文本大小计算工具里,得到的“大小”就是这段文本的 UTF-8 字节数。文本大小计算是我们自己的产品 Digily Link 提供的工具。它在你的浏览器里用 Blob 计算 UTF-8 字节数,按当前工具代码,计算过程不需要把文本提交到服务器;结果以 KB 显示时,1 KB 按 1024 字节计算。

utf8mb4 列里保存的同样是 UTF-8 字节,所以工具给出的字节数应当与这段文本存入 utf8mb4 列后 LENGTH() 的结果一致。不过工具读取文本框时会把换行统一成 LF,每个换行按 1 字节计算,如果实际存入的文本带 CRLF 换行,工具的结果会少算这部分字节。我们没有用真实的 MySQL 做过对照测试,重要场景请再用上一节的 SQL 核对一遍。建表前想估算某段典型内容的长度,可以在文本大小计算里粘贴文本,先看它在 UTF-8 下占多少字节。

常见问题

中文和英文混合时,VARCHAR(255) 能存多少?

仍然是 255 个字符,与中英文如何混合无关。区别只在字节数上,比如示例标题“MySQL入门30讲”是 10 个字符,其中字母和数字各占 1 字节,三个汉字各占 3 字节,共 16 字节。

存表情符号时报错怎么办?

先用 SHOW CREATE TABLE 查看这一列的字符集。如果是 utf8mb3,它无法存储表情符号这类增补平面字符,请改用 utf8mb4,迁移步骤以 MySQL 官方文档为准。

为什么常写 varchar(255) 而不是 256?

在每个字符最多占 1 字节的字符集里,255 是能用 1 字节长度前缀的最大长度(推算)。在 utf8mb4 下,从 VARCHAR(64) 起就已经是 2 字节前缀,255 和 256 在前缀上没有区别。

0 个评分中的 0 个