MySQL y MariaDB: TO_BASE64 y FROM_BASE64
SELECT TO_BASE64('héllo wörld');
-- aMOpbGxvIHfDtnJsZA== (connection charset utf8mb4)
SELECT CONVERT(FROM_BASE64('aMOpbGxvIHfDtnJsZA==') USING utf8mb4);
-- héllo wörld
TO_BASE64 codifica los bytes de la cadena en su juego de caracteres. Con utf8mb4 obtienes UTF-8; una columna latin1 da bytes Latin-1, así que TO_BASE64(CONVERT('héllo' USING latin1)) devuelve aOlsbG8= en lugar de aMOpbGxv. FROM_BASE64 devuelve una cadena binaria; CONVERT(... USING utf8mb4) la convierte de nuevo en texto.
TO_BASE64 corta las líneas a 76 caracteres, como MIME:
SELECT LENGTH(TO_BASE64(REPEAT('x', 60))); -- 81 (80 chars + 1 newline)
SELECT REPLACE(TO_BASE64(REPEAT('x', 60)), '\n', ''); -- single line, 80 chars
Una entrada no válida no provoca ningún error. FROM_BASE64 devuelve NULL:
| Entrada | Resultado |
|---|---|
aGk= | hi |
aGk | NULL (sin relleno) |
aGk=!! | NULL |
PDw_Pz8-Pg== | NULL (URL-safe) |
a | NULL |
aGl= | hi (acepta bits de relleno distintos de cero) |
'aGVs\nbG8K', 'aGVs bG8K' | hello\n (ignora los espacios en blanco) |
Conversión URL-safe con funciones de cadena:
SELECT TRIM(TRAILING '=' FROM REPLACE(REPLACE(TO_BASE64('<<???>>'), '+', '-'), '/', '_'));
-- PDw_Pz8-Pg
SELECT FROM_BASE64(CONCAT(
REPLACE(REPLACE('PDw_Pz8-Pg', '-', '+'), '_', '/'),
REPEAT('=', (4 - LENGTH('PDw_Pz8-Pg') % 4) % 4)));
-- <<???>>
Con valores más largos, envuelve también el codificador en REPLACE(..., '\n', ''). Las dos funciones existen desde MySQL 5.6 y también en MariaDB.
PostgreSQL: encode y decode
PostgreSQL trabaja con bytea. Convierte el texto con convert_to y vuelve atrás con convert_from:
SELECT encode(convert_to('héllo wörld', 'UTF8'), 'base64');
-- aMOpbGxvIHfDtnJsZA==
SELECT convert_from(decode('aMOpbGxvIHfDtnJsZA==', 'base64'), 'UTF8');
-- héllo wörld
Igual que MySQL, encode(..., 'base64') corta a 76 caracteres; psql muestra el salto de línea como un + al final de la línea. Quítalo con replace(encode(x, 'base64'), E'\n', '').
A diferencia de MySQL, una entrada no válida provoca un error:
decode('aGk', 'base64')
ERROR: invalid base64 end sequence
HINT: Input data is missing padding, is truncated, or is otherwise corrupted.
decode('PDw_Pz8-Pg==', 'base64')
ERROR: invalid symbol "_" found while decoding base64 sequence
aGk=!! falla con invalid symbol "!" y a con invalid base64 end sequence. Los espacios en blanco, incluidos saltos de línea y espacios, se ignoran, y aGl= se acepta.
PostgreSQL 17 y 18 no tienen formato base64url (unrecognized encoding: "base64url"), así que convierte con translate:
SELECT translate(rtrim(encode('<<???>>'::bytea, 'base64'), '='), '+/', '-_');
-- PDw_Pz8-Pg
SELECT convert_from(decode(
rpad(translate('PDw_Pz8-Pg', '-_', '+/'), (length('PDw_Pz8-Pg') + 3) / 4 * 4, '='),
'base64'), 'UTF8');
-- <<???>>
Para validar sin abortar una transacción, envuelve decode en una función PL/pgSQL con un bloque EXCEPTION WHEN others que devuelva NULL.
SQL Server: el truco XML base64Binary
Antes de SQL Server 2025 no hay ninguna función Base64. El tipo XML convierte entre varbinary y xs:base64Binary, que es Base64:
-- encode
DECLARE @bin varbinary(max) = CAST('hi' AS varbinary(max));
SELECT CAST('' AS xml).value('xs:base64Binary(sql:variable("@bin"))', 'varchar(max)');
-- aGk=
-- decode
DECLARE @b64 varchar(max) = 'aGk=';
SELECT CAST('' AS xml).value('xs:base64Binary(sql:variable("@b64"))', 'varbinary(max)');
-- 0x6869
FOR XML ... BINARY BASE64 y FOR JSON también emiten las columnas varbinary como Base64: SELECT CAST('hi' AS varbinary(max)) AS bin FOR JSON PATH devuelve [{"bin":"aGk="}]. La conversión XML no corta líneas: 60 bytes salieron como una única cadena de 80 caracteres.
Los métodos XML necesitan QUOTED_IDENTIFIER ON. sqlcmd lo desactiva por defecto, lo que da Msg 1934: SELECT failed because the following SET options have incorrect settings: 'QUOTED_IDENTIFIER'. Pasa -I o ejecuta SET QUOTED_IDENTIFIER ON.
Codificación de texto en SQL Server
nvarchar es UTF-16LE, así que CAST(N'héllo wörld' AS varbinary(max)) se codifica como aADpAGwAbABvACAAdwD2AHIAbABkAA==, que otros sistemas decodifican con huecos entre las letras. Para UTF-8 (SQL Server 2019+), pasa antes por una intercalación UTF-8:
DECLARE @bin varbinary(max) = CAST(CAST(N'héllo wörld'
COLLATE Latin1_General_100_CI_AS_SC_UTF8 AS varchar(max)) AS varbinary(max));
-- encodes to aMOpbGxvIHfDtnJsZA==
Para decodificar de vuelta a UTF-8 hace falta un destino UTF-8. Un simple CAST(@raw AS varchar(max)) en una base de datos con la intercalación predeterminada SQL_Latin1_General_CP1_CI_AS muestra héllo wörld. Insertar los bytes en una columna declarada como varchar(max) COLLATE Latin1_General_100_CI_AS_SC_UTF8 da héllo wörld. Para datos UTF-16 basta con CAST(@raw AS nvarchar(max)).
Errores
Con un literal de cadena, un Base64 incorrecto falla en tiempo de compilación: Msg 9319: XQuery [value()]: Static simple type validation: Invalid simple type value 'aGk'. La misma entrada pasada mediante sql:variable devuelve NULL. La falta de relleno, los caracteres URL-safe (PDw_Pz8-Pg==) y los bits de relleno distintos de cero (aGl=) se rechazaron; un salto de línea dentro de la cadena se aceptó.
SQL Server 2025: BASE64_ENCODE y BASE64_DECODE
SQL Server 2025 (17.x) y Azure SQL añaden funciones de verdad, incluido un indicador URL-safe:
SELECT BASE64_ENCODE(0x3C3C3F3F3F3E3E); -- PDw/Pz8+Pg==
SELECT BASE64_ENCODE(0x3C3C3F3F3F3E3E, 1); -- PDw_Pz8-Pg (url_safe, no padding)
SELECT BASE64_DECODE('PDw_Pz8-Pg'); -- 0x3C3C3F3F3F3E3E
BASE64_ENCODE solo admite varbinary; pasarle varchar falla con Msg 8116: Argument data type varchar(max) is invalid for argument 1 of base64_encode function. BASE64_DECODE acepta los dos alfabetos, con o sin relleno, y también aGl=. Una entrada no válida como aGk=!! o a provoca Msg 9803: Invalid data for type "Base64Decode".
Trampas comunes a todas las bases de datos
- El juego de caracteres de la entrada. El mismo texto da un Base64 distinto en una columna
latin1, en unautf8mb4y en unanvarchar. Decide usar bytes UTF-8 y convierte de forma explícita. - Saltos de línea ocultos. MySQL y PostgreSQL cortan a 76 caracteres. Los consumidores de JSON y las cabeceras HTTP se rompen con el
\nincrustado. NULLsilenciosos. MySQL y el truco XML de SQL Server devuelvenNULLcon una entrada incorrecta, y unJOINo unWHEREdescartan esas filas sin avisar.- Valores grandes. Codificar un BLOB en una consulta mueve un 33 % más de datos por la red. Para revisar a mano un valor guardado, selecciona el Base64 y ábrelo con Base64 a archivo o Base64 a hex.
Preguntas frecuentes
¿Por qué FROM_BASE64 de MySQL devuelve NULL?
MySQL devuelve NULL en lugar de un error cuando la entrada no es válida: falta de relleno, - o _ de URL-safe o caracteres basura. Revisa la entrada con el validador Base64 y corrige las cadenas URL-safe con REPLACE antes de decodificar.
¿Por qué la salida de TO_BASE64 de MySQL tiene saltos de línea?
TO_BASE64 sigue la convención MIME e inserta un salto de línea cada 76 caracteres. Envuélvela en REPLACE(TO_BASE64(x), '\n', '') para obtener una sola línea.
¿SQL Server tiene una función Base64?
SQL Server 2025 y Azure SQL tienen BASE64_ENCODE y BASE64_DECODE. Las versiones anteriores no tienen función, pero la conversión XML xs:base64Binary hace el trabajo.
¿Debo guardar archivos como Base64 en la base de datos?
Normalmente no. Una columna binaria (BLOB, bytea, varbinary) guarda los mismos datos ocupando alrededor de un 25 % menos y se ahorra la conversión. Codifica solo cuando envíes los datos a un sistema que necesite texto. Consulta el aumento de tamaño de Base64.