SQL databases store hex values as raw bytes, encoded strings, or varbinary columns, and converting hex to text in SQL means turning that byte sequence back into characters using the engine's built-in functions. MySQL exposes UNHEX() and pairs it with CONVERT(... USING utf8mb4); SQL Server returns varbinary as a 0x-prefixed hex string that you re-cast to varchar; Kingbase and other Chinese-engine forks lean on DECODE() combined with an explicit CONVERT charset; PostgreSQL typically relies on encode() and decode() with a bytea intermediate. Each approach has subtle failure modes: a default replacement decoder can substitute the U+FFFD character when bytes are malformed, a varchar target can silently truncate, and a connection collation that does not match the source bytes can return mojibake. A browser-based Hex to Text Converter that decodes UTF-8 in fatal mode is a reliable second opinion — paste the SQL output as continuous hex, whitespace-separated hex, or 0xNN tokens, and the tool either returns the exact text or refuses to decode, never a partial replacement string.

SQL Functions That Convert Hex to Text Across Engines
Several SQL dialects ship with different hex-to-text primitives, and knowing which one is available shapes how you read stored data back as characters. MySQL's UNHEX() takes a hex literal such as UNHEX('48656C6C6F') and returns the corresponding bytes; combining it with CONVERT(... USING utf8mb4) tells the server to interpret those bytes as UTF-8 instead of the connection's default character set. SQL Server has no direct UNHEX, but a SELECT CAST(0x48656C6C6F AS varchar(50)) expression uses the same 0x literal syntax to declare inline hex bytes and then projects them as a string, while CONVERT(varchar(100), 0x48656C6C6F) does the same thing through the conversion function. PostgreSQL converts the other way — encode() turns text into hex and decode() goes from hex to bytes — so the round trip looks like convert_from(decode('48656C6C6F', 'hex'), 'UTF8'). Kingbase follows a DECODE-style API where DECODE('E4BDA0E5A5BD', 'hex') yields raw bytes that must then be CONVERT-ed with an explicit 'UTF8' target charset to land on 你好. These four approaches cover the vast majority of SQL hex-to-text questions, and the differences between them explain most of the "works on my machine" reports when SQL Server reads a MySQL export.
| SQL engine | Primary hex-to-text function | Required charset step | Default output type | Typical failure mode |
|---|---|---|---|---|
| MySQL | UNHEX('hex') | CONVERT(... USING utf8mb4) | varbinary then string | Returns binary; connection charset mismatch shows mojibake |
| SQL Server | CAST(0x... AS varchar) | Implicit via column collation | varchar | Replacement char or truncation at collation boundary |
| PostgreSQL | decode('hex', 'hex') | convert_from(..., 'UTF8') | text | Errors on non-hex input; no replacement fallback |
| Kingbase | DECODE('hex', 'hex') | CONVERT(..., 'UTF8') | varchar | Source charset must match bytes or output is wrong |
Why SQL Conversions Alone Can Mislead
A successful-looking SQL result does not guarantee a correct decode, because each engine handles malformed UTF-8 differently and the visible output can mask real damage. MySQL's UNHEX() returns binary bytes regardless of whether those bytes form valid UTF-8; if you then CONVERT them USING utf8mb4 without fatal mode, the server can substitute U+FFFD for truncated multibyte sequences, encoded surrogates, and overlong forms, leaving you with a string that looks like data but is actually a partial reconstruction. SQL Server's CAST from varbinary to varchar uses the column or expression collation, so a hex payload encoded in UTF-8 that lands in a Latin1 column displays as mojibake rather than failing — the bytes are technically converted but mean something else. PostgreSQL's convert_from throws on invalid UTF-8, which is the safest behavior of the four, but the error message often hides the exact byte offset and forces you to bisect the input. Kingbase's DECODE path inherits the same replacement-character risk as MySQL when the target charset is permissive. Across all of these engines, the deeper issue is that the SQL engine's idea of valid UTF-8 can be looser than RFC 3629, so a hex string your SQL query happily turns into text might still contain bytes that a strict decoder rejects.
Verify SQL Hex Output in a Strict UTF-8 Browser Tool
When you need certainty about what a hex value should actually say, paste the SQL output into the Hex to Text Converter and let a fatal UTF-8 decoder be the final judge. The tool runs locally in your current browser tab, so database contents never leave your machine, and it accepts the three hex shapes that SQL engines typically emit.
- Run the SQL query that returns hex (for example SELECT HEX(column) FROM table or a SELECT that returns varbinary as a 0x string) and copy the resulting hex string without reformatting it.
- Open the Hex to Text Converter and paste the hex into the input field — continuous pairs such as 48656C6C6F, ASCII-whitespace-separated groups such as 48 65 6c 6c 6f, or explicit 0xNN byte tokens such as 0x48 0x65 0x6C 0x6C 0x6F all work once the matching syntax option is enabled.
- Toggle the ASCII whitespace separator option if your SQL output includes spaces, tabs, or line breaks between byte groups; toggle the 0x prefix option if the string starts with 0x as SQL Server varbinary casts often produce.
- Click Decode and read either the resulting text or the error. Fatal mode means an odd nibble, a stray continuation byte, a truncated three-byte sequence, an encoded surrogate, or a value above U+10FFFF stops the decode entirely — no replacement character and no partial prefix is returned.
- If the decode succeeds, copy the text from the read-only field using the copy button (the browser asks for clipboard permission once) or select it manually if permission is denied.
For a deeper walkthrough of catching malformed bytes at the input stage, see how to convert a hex string to text without silent errors.
Plain vs 0xNN Output From SQL Queries
SQL Server's CAST(0x48656C6C6F AS varchar(50)) returns the bytes themselves rather than a hex string, but the moment you wrap the value in a string-returning function the result often prints as a 0x-prefixed hex literal, which is the second accepted syntax in the Hex to Text Converter. When the 0x option is enabled the parser switches to a strict mode that requires every token to be exactly 0xNN — no 0x041, no 0x410x42, no comma between tokens, and no mixing with plain unprefixed groups in the same string. MySQL's HEX(column) on the other hand emits a plain hex string without the 0x prefix, so the same input pastes as 48656C6C6F and decodes under plain mode where the only constraint is an even number of hex digits per group. PostgreSQL's encode(bytes, 'hex') falls into the same plain-mode camp, and Kingbase's DECODE source string is plain as well. Knowing which mode to enable matters because the parser will reject any prefix it sees if 0x mode is on but the rest of the input does not match, and disabling prefixes rejects 0x input outright rather than silently stripping them, per the WHATWG Encoding Standard decoder contract documented on MDN.
Reading Common SQL Hex Strings as UTF-8
SQL hex values usually look opaque, but each pair of hex digits is just one byte, and most working data is ASCII, so you can often predict what the decoder should return. Take a hex string you might see in a MySQL UNHEX example: 48656C6C6F20576F726C64. Split into byte pairs and read each from the ASCII table — 0x48 is 'H', 0x65 is 'e', 0x6C is 'l', 0x6C is 'l', 0x6F is 'o', 0x20 is the space character, 0x57 is 'W', 0x6F is 'o', 0x72 is 'r', 0x6C is 'l', 0x64 is 'd'. The full sequence therefore reads "Hello World" — 11 bytes, 11 characters, no multibyte sequences involved. A more interesting case is E4BDA0E5A5BD, the UTF-8 encoding of 你好 from the Kingbase DECODE example: 0xE4 0xBD 0xA0 is the three-byte form of U+4F60 (你), and 0xE5 0xA5 0xBD is the three-byte form of U+597D (好). Pasting either string into the Hex to Text Converter with the ASCII whitespace separator enabled returns the expected text, and pasting a deliberately broken version such as E4BD (a truncated three-byte sequence) returns an error rather than a replacement character — confirming that the SQL bytes did not survive transport intact.
When SQL Hex Decodes to Replacement Characters
If you have ever seen a black diamond with a question mark in a SQL result, you have watched the database silently rewrite damaged bytes. Replacement characters appear most often when a UTF-8 string is round-tripped through a column or connection whose character set is something narrower — Latin1, ASCII, or a partial multibyte collation — because the destination engine does not know what to do with the high bytes it cannot represent. They also appear when a hex literal contains an invalid UTF-8 fragment such as a stray continuation byte 0x80 or an overlong form like C0 AF that should have encoded U+002F but uses two forbidden bytes. The browser-side Hex to Text Converter avoids this outcome entirely by configuring the WHATWG TextDecoder in fatal mode per RFC 3629: invalid bytes, truncated sequences, encoded surrogates, and values above U+10FFFF all produce a hard error and zero output, so the same hex string that prints as "Hello��World" in a permissive SQL console either decodes cleanly to "HelloWorld" or refuses to decode at all. That asymmetry is the point — silent replacement is convenient for casual reads but it hides data corruption, and a strict browser check is the cheapest way to know which one you have.
Related Hex Workflows From SQL Output
A SQL query rarely stops at hex-to-text, and a few adjacent paths come up often enough to flag here. When the SQL output is a formatted memory dump with addresses such as 00000000 48 65 6c 6c 6f ... rather than a clean byte column, extract only the byte column using a trusted workflow before pasting it, because the tool does not strip addresses or skip whitespace beyond the five ASCII characters it knows about. When the SQL column stores raw binary rather than hexadecimal — for instance a BLOB payload extracted with CAST(column AS varchar(MAX)) — use Binary to Text instead, since hex and binary are different notations and the parser will reject binary input. When the SQL output is Base64 rather than hex, route it through Base64 Encode / Decode first and then convert the resulting bytes to hex if needed. None of these paths upload data to a server; each tool runs locally in the current browser tab and shares the same fatal-UTF-8 strictness, so the verification property you build up with the Hex to Text Converter carries over to every other step.
If you're weighing options, Base64 to Hex Free No Sign Up: Convert in Browser covers this in detail.