MD5 Hash Length: 128 Bits, 16 Bytes, 32 Hex Characters

An MD5 hash is always 128 bits long. Written the usual way, as hexadecimal, that is exactly 32 characters, whatever you hashed: an empty string, a password or a 4 GB ISO image. If you are looking at an "MD5" that is 31 or 33 characters, or 24, the digest is not wrong — something between the hash function and your screen changed its representation. This article gives the exact numbers, explains where each one comes from, and shows the bugs that produce the odd lengths.

MD5 length in bits, bytes and characters

RFC 1321, the MD5 specification, defines the output as a 128-bit message digest. Every other number people quote is the same 128 bits written differently:

bits            128
raw bytes       16      (128 / 8)
hex characters  32      (each byte = 2 hex digits)
Base64          24      (22 + "==" padding; 22 without padding)

So the answer to the quiz question "what is the size of the hash value produced by MD5: 128 bits, 256 bits, 64 bits, or depends on the size of the input" is 128 bits. 256 bits is SHA-256, and "depends on the input" is never true for a cryptographic hash: the output size is fixed by the algorithm.

The 32-character form is what md5sum, PHP md5(), Python hexdigest() and almost every online MD5 hash generator print. The 16-byte form is what the hash function actually returns before anyone formats it.

Why the input size never changes the length

MD5 pads the message to a multiple of 512 bits, appends the original length, and then processes it one 512-bit block at a time. Each block is mixed into a state of four 32-bit words, A, B, C and D. After the last block those four words, 4 × 32 = 128 bits, are the digest. There is no step where a longer message gets a longer state, so there is nowhere for extra length to go.

You can check it with any two inputs of very different sizes:

$ printf '' | md5sum
d41d8cd98f00b204e9800998ecf8427e  -
$ printf 'hello' | md5sum
5d41402abc4b2a76b9719d911017c592  -
$ printf 'The quick brown fox jumps over the lazy dog' | md5sum
9e107d9d372bb6826bd81d3542a419d6  -

All three are 32 characters. The flip side is that the length tells you nothing about the input: a 32-character MD5 does not reveal whether the original was one byte or one gigabyte.

"Are MD5 hashes different lengths?" The 31-character bug

A real search behind this page pasted two values, 87273b55497c8ddc519d05979462d874 and 3e5a9ff2de9e6d7531f31fe695a723b, and asked whether one of them is wrong. The first is 32 characters, the second 31. MD5 never produces 31 characters, so the second value has lost a digit — and the usual cause is a leading zero dropped during formatting.

The classic culprit is converting the digest bytes to a number and printing that number in hex. Numbers do not keep leading zeros, so about one hash in sixteen (every digest whose first hex digit is 0) comes out one character short, and one in 256 comes out two short. In Java the well-known pattern is new BigInteger(1, digest).toString(16); Python has the same trap:

import hashlib

h = hashlib.md5(b"user5")
print(h.hexdigest())                                  # 0a791842f52a0acfbb3a783378c066b8
print(format(int.from_bytes(h.digest(), "big"), "x"))  # a791842f52a0acfbb3a783378c066b8  (31 chars)
print(format(int.from_bytes(h.digest(), "big"), "032x"))  # zero-padded: back to 32

The fix is to pad to 32 characters (String.format("%032x", new BigInteger(1, digest)) in Java, 032x in Python) or, better, use a byte-wise hex encoder that cannot drop anything: HexFormat.of().formatHex(digest) on Java 17 and later, hexdigest() in Python. Other ways to end up with a wrong length are a stray newline in the hashed text (the hash is still 32 characters but different), copying from a fixed-width column, and a field that silently truncates.

Hex versus Base64 MD5

A 24-character string ending in == can also be an MD5. HTTP's Content-MD5 header, Amazon S3 and Azure Blob Storage expect the 16 raw bytes encoded as Base64, not the hex text. The two forms of the same digest look nothing alike:

$ printf 'hello' | openssl dgst -md5 -binary | base64
XUFAKrxLKna5cZ2REBfFkg==          # 24 chars: Base64 of the 16 bytes (correct)

$ printf 'hello' | md5sum | cut -d' ' -f1 | tr -d '\n' | base64
NWQ0MTQwMmFiYzRiMmE3NmI5NzE5ZDkxMTAxN2M1OTI=   # 44 chars: Base64 of the hex text (wrong)

If you see a 44-character Base64 value where an MD5 was expected, someone encoded the 32 hex characters instead of the 16 bytes. Storage APIs reject it with a digest mismatch even though the file is fine. The MD5 and Base64 article covers that conversion in more detail.

Sizing a database column for MD5

Because the length is fixed, the column should be fixed too. Hex is readable in query results; binary is half the size and indexes faster:

-- hex: 32 characters, store lower case
checksum CHAR(32) NOT NULL

-- raw bytes: 16 bytes
checksum BINARY(16) NOT NULL      -- MySQL / MariaDB
checksum BYTEA NOT NULL           -- PostgreSQL
CHECK (octet_length(checksum) = 16)

Avoid VARCHAR(255) out of habit: it accepts a 31-character value from the bug above, or a value with a trailing space, and the lookup then silently never matches. Hex also has a case problem. md5sum and PHP print lower case, while PowerShell's Get-FileHash prints upper case (9E107D9D…). Normalise to one case on the way in, or compare under a case-insensitive collation, otherwise identical files look different.

Recognising MD5 by length, and its limits

Length is a quick way to guess which algorithm produced an unlabelled hex digest: 32 characters is MD5 (or the older MD4 and NTLM, which share the size), 40 is SHA-1, 64 is SHA-256 and 128 is SHA-512. A $1$ prefix marks an MD5-crypt password hash, which is a different, longer format. The SHA-256 hash length page lists the full set.

Two warnings. First, a 32-character string that contains letters after f is not hex at all, so it is not a raw MD5. Second, length only narrows the options; it does not prove the algorithm. Hash the original yourself and compare.

And because 128 bits is short by modern standards and MD5 is broken for collisions, its length is fine for checksums and cache keys but not for signatures, certificates or password storage. Use SHA-256 or a password hash such as Argon2 or bcrypt there.

Sources and further reading

RFC 1321 (The MD5 Message-Digest Algorithm) defines the 128-bit output and the padding and four-word state described above. RFC 6151 records why MD5 must not be used where collision resistance matters. RFC 4648 defines Base64, and RFC 1864 the Content-MD5 header that carries the Base64 form. The Python hashlib and PHP md5() manuals document the hex and raw-byte outputs used in the examples.

Frequently asked questions

How long is an MD5 hash?

Always 128 bits. That is 16 bytes, written as 32 hexadecimal characters in the usual form, or 24 characters in Base64. The length is the same for every input.

How many bits is MD5?

MD5 produces a 128-bit digest, as defined in RFC 1321. It is not 256 bits (that is SHA-256) and it does not depend on the size of the input.

How many characters is an MD5 hash?

32 characters in hexadecimal, using the digits 0–9 and letters a–f. If you count 31, a leading zero was almost certainly dropped by code that formatted the digest as a number.

Why is my MD5 hash only 31 characters?

The digest started with a 0 and was printed as an integer, for example with Java's BigInteger.toString(16), which drops leading zeros. Pad it to 32 characters or use the library's hex output.

Is a 24-character string an MD5 hash?

It can be. A 24-character value ending in == is the Base64 encoding of the 16 raw MD5 bytes, the format used by Content-MD5, Amazon S3 and Azure. Decode it to bytes and hex-encode them to compare with a 32-character hash.

What database column type should I use for MD5?

CHAR(32) for lower-case hex, or BINARY(16) in MySQL and BYTEA in PostgreSQL for the raw bytes. A fixed size rejects malformed values; VARCHAR(255) lets truncated or padded hashes in.