Skip to content
DonateБГ

Networking

Magic bytes

Bitcoin magic bytes are the 4-byte marker at the start of every P2P message. Mainnet uses f9beb4d9, and each test network has its own value.

By Dimitar Zurnov · Updated 4 Nov 2026
Adapted from Learn Me a Bitcoin by Greg Walker.

Magic bytes are the four bytes at the start of every message on the Bitcoin peer-to-peer network. They mark where a message begins, and they name the network the message belongs to. On mainnet they are f9beb4d9. Each test network has its own value, so a node can tell which network a peer is on from the first four bytes it receives.

Which magic bytes belong to which network?

Network Magic bytes Default port
Mainnet f9beb4d9 8333
Testnet3 0b110907 18333
Testnet4 1c163f28 48333
Signet derived from the signet challenge 38333
Regtest fabfb5da 18444

The values come from the chain parameters in the Bitcoin Core source. Testnet4 is described in BIP 94. Signet has no fixed magic bytes. Bitcoin Core computes them from the challenge that defines the signet you use, so a signet with a different challenge has different bytes.

Nodes on each network listen on the default port in the table. For the protocol itself, see networking.

A byte stream holds several messages back to back, and each one starts with the same four magic bytes. f9 be b4 d9 version message command, length, checksum, payload f9 be b4 d9 verack message command, length, checksum, payload f9 be b4 d9 ping message command, length, checksum, payload Read four bytes, compare, then read the rest.
Each message begins with the marker. The reader checks it before it reads the rest.

What do magic bytes do?

Nodes send messages over a TCP connection, and TCP delivers a stream of bytes with no built-in message boundaries. When your code reads that stream, it needs a way to find where each message starts. The magic bytes are that marker. Read four bytes, compare them with the marker for the network you expect, then read the header and the payload.

They are not a checksum. The same four bytes could appear inside a payload, so a reader cannot rely on them alone. The header's checksum is what confirms a message is intact, and the version message shows how the header fields fit together.

Why these four bytes?

Bitcoin Core's source once explained the choice in a comment, and that comment has since been removed. The shape of the bytes still makes a false match unlikely, and the reasons are simple to check.

  • Not text. f9 cannot appear anywhere in valid UTF-8, and the other three bytes sit above the ASCII range. A string in a script or a text field will almost never contain them by accident.
  • Large numbers. Read as a 32-bit integer, f9beb4d9 is 4,190,024,921 in big-endian order, and 3,652,501,241 in little-endian order. Fields such as a version or a count are small, so they rarely take these values.
  • Not guaranteed. The same bytes can appear inside a block or a transaction. The marker helps find where a message probably begins, and tells you which network it belongs to. It does not prove the message is valid.

How do you check the network from a message?

Compare the first four bytes with the table. A mismatch means the peer is on another network, or the stream is out of step. In either case, drop the connection and start from a known message boundary.

NETWORKS = {
    bytes.fromhex("f9beb4d9"): "mainnet",
    bytes.fromhex("0b110907"): "testnet3",
    bytes.fromhex("1c163f28"): "testnet4",
    bytes.fromhex("fabfb5da"): "regtest",
}

def network_of(message_start: bytes) -> str:
    return NETWORKS.get(bytes(message_start[:4]), "unknown network")

print(network_of(bytes.fromhex("f9beb4d976657273")))  # mainnet

Signet is missing from this table on purpose, because its bytes depend on the challenge you use.

Where can you see them?

The genesis block is stored in the blockchain files on disk with the magic bytes in front. The first eight bytes of blk00000.dat are f9 be b4 d9 1d 01 00 00. The first four are the magic bytes. The next four are the block size, 1d010000, which is 285 bytes in little-endian order. The genesis block on Explore21 is that same block.

A version message on testnet3 starts with 0b110907 instead. The layout is the same on every network, and only the first four bytes change.

In this section: Networking

All of Bitcoin from zero

Something look wrong? Tell us