Deep Dive: mining.subscribe, mining.authorize, and mining.configure
The Handshake That Starts Everything
Section titled “The Handshake That Starts Everything”Before a miner can hash a single block header, it needs to complete a handshake with the pool. This handshake is where the miner and pool agree on the rules of engagement: how to identify shares, how much nonce space the miner gets, and what protocol extensions are in play.
In this article, we will dissect three methods that make up this handshake: mining.configure, mining.subscribe, and mining.authorize. We will look at every field, every edge case, and every quirk.
mining.configure: Negotiating Extensions
Section titled “mining.configure: Negotiating Extensions”In modern mining, mining.configure is actually the first message sent — even before mining.subscribe. It was added later as a protocol extension (BIP 310) to handle features that the original Stratum design did not anticipate, most importantly version rolling.
Why Version Rolling Exists
Section titled “Why Version Rolling Exists”The Bitcoin block header has a version field (4 bytes). Originally, this was meant to signal which protocol version the block uses. But mining hardware discovered that you could repurpose unused bits in this field as extra nonce space. Instead of only iterating over the 4-byte nonce, the ASIC can also flip bits in the version field, effectively multiplying the search space.
This technique is closely related to AsicBoost, an optimization that certain ASIC designs use to speed up SHA-256 hashing. For version rolling to work, the miner and pool need to agree on which bits of the version field the miner is allowed to change. That is what mining.configure negotiates.
The Request
Section titled “The Request”{ "id": 1, "method": "mining.configure", "params": [ ["version-rolling"], { "version-rolling.mask": "1fffe000", "version-rolling.min-bit-count": 2 } ]}Let us break down the parameters:
First parameter: extension list
An array of extension names the miner wants to use. Currently, "version-rolling" is by far the most common (and often the only) extension. Other extensions could be added in the future.
Second parameter: extension parameters A dictionary of settings for each requested extension.
-
version-rolling.mask: A hexadecimal bitmask ("1fffe000") that represents which bits of the version field the miner wants to modify. In binary,1fffe000is0001 1111 1111 1111 1110 0000 0000 0000. The1bits are the ones the miner wants to roll. -
version-rolling.min-bit-count: The minimum number of bits the miner needs to be able to roll. If the pool’s mask provides fewer rollable bits than this, the miner considers the negotiation failed.
The Response
Section titled “The Response”{ "id": 1, "result": { "version-rolling": true, "version-rolling.mask": "1fffe000" }, "error": null}version-rolling: true— The pool agrees to support version rolling.version-rolling.mask— The mask the pool actually allows. This might be a subset of what the miner requested. The miner must AND this with its own mask to determine the final set of rollable bits.
What If the Pool Does Not Support It?
Section titled “What If the Pool Does Not Support It?”If the pool does not support the mining.configure method at all, it may respond with an error or simply ignore the message. Well-behaved miners should handle this gracefully and proceed without version rolling. Some older pools will respond with:
{ "id": 1, "result": { "version-rolling": false }, "error": null}In this case, the miner must not modify the version field in any block headers it constructs.
mining.subscribe: Registering with the Pool
Section titled “mining.subscribe: Registering with the Pool”After mining.configure (or immediately upon connecting, for miners that do not use extensions), the miner sends mining.subscribe. This is the most important handshake message because it establishes the miner’s identity within the pool’s system and assigns the extraNonce parameters that define the miner’s search space.
The Request
Section titled “The Request”{ "id": 2, "method": "mining.subscribe", "params": [ "cgminer/4.12.1", null ]}Parameter 1: User agent ("cgminer/4.12.1")
A string identifying the mining software. This is informational — the pool uses it for statistics and debugging. Common values include:
"bmminer/2.0.0"(Bitmain firmware)"cgminer/4.12.1"(open-source miner)"BraiinsOS/2023-06"(Braiins firmware)"NerdMiner/1.0"(hobby miner projects)
Parameter 2: Previous subscription ID (null)
Used for session resumption. On a fresh connection, this is null. If the miner is reconnecting after a disconnect, it can pass the subscription ID from the previous session. If the pool still has that session in memory, it may restore the same extraNonce1, allowing the miner to resume more quickly.
The Response (Dissected Field by Field)
Section titled “The Response (Dissected Field by Field)”{ "id": 2, "result": [ [ ["mining.set_difficulty", "b4b6693b72a50c7116db18d6497cac52"], ["mining.notify", "ae6812eb4cd7735a302a8a9dd95cf71f"] ], "08000002", 4 ], "error": null}The result is an array with three elements. Let us examine each one.
Element 1: Subscription Pairs
Section titled “Element 1: Subscription Pairs”[ ["mining.set_difficulty", "b4b6693b72a50c7116db18d6497cac52"], ["mining.notify", "ae6812eb4cd7735a302a8a9dd95cf71f"]]This is an array of two-element arrays, each pairing a method name with a subscription ID. These tell the miner:
- “You are subscribed to
mining.set_difficultynotifications, and your subscription ID for that isb4b6693b72a50c7116db18d6497cac52.” - “You are subscribed to
mining.notifynotifications, and your subscription ID isae6812eb4cd7735a302a8a9dd95cf71f.”
In practice, most mining software ignores these subscription IDs. They were originally intended to allow selective unsubscription, but no one actually uses that feature. The miner simply expects to receive mining.set_difficulty and mining.notify messages after subscribing.
Element 2: extraNonce1
Section titled “Element 2: extraNonce1”"08000002"This is the extraNonce1 value, a hex string assigned by the pool. This is critically important. Let us understand why.
In Bitcoin mining, every miner is constructing a slightly different block. Even though they all build on the same previous block hash and include similar transactions, they need some way to produce different hashes. The nonce field in the block header provides one dimension of variation, but 4 bytes (about 4.3 billion values) is not enough for modern ASICs that compute trillions of hashes per second.
The extraNonce is additional nonce space embedded in the coinbase transaction (the special transaction that pays the mining reward). The pool splits this space into two parts:
- extraNonce1: Assigned by the pool, unique to each miner/session. The miner must not change this.
- extraNonce2: The miner’s own space to iterate over.
When constructing the coinbase transaction, the miner concatenates: coinbase1 + extraNonce1 + extraNonce2 + coinbase2. By varying extraNonce2, the miner changes the coinbase transaction hash, which changes the merkle root, which changes the block header, which produces completely different SHA-256 hashes.
In this example, "08000002" is 4 bytes (8 hex characters). Every share this miner submits will include these bytes in the coinbase transaction, allowing the pool to identify which miner produced it.
Element 3: extraNonce2 Size
Section titled “Element 3: extraNonce2 Size”4This integer tells the miner how many bytes it can use for extraNonce2. In this example, 4 bytes means the miner has 2^32 (about 4.3 billion) possible extraNonce2 values.
Combined with the 4-byte header nonce, this gives:
- 4.3 billion (nonce) x 4.3 billion (extraNonce2) = approximately 1.8 x 10^19 possible combinations per job
For reference, a modern Antminer S21 hashes at about 200 TH/s. At that rate, it would take about 25 hours to exhaust this combined space — far longer than a job typically lasts (usually seconds to minutes).
Session Resumption
Section titled “Session Resumption”When a miner reconnects after a disconnect, it can attempt to resume its previous session:
{ "id": 2, "method": "mining.subscribe", "params": [ "cgminer/4.12.1", "ae6812eb4cd7735a302a8a9dd95cf71f" ]}The second parameter is the previous subscription ID (from the mining.notify subscription pair). If the pool still has this session:
Successful resumption:
{ "id": 2, "result": [ [ ["mining.set_difficulty", "b4b6693b72a50c7116db18d6497cac52"], ["mining.notify", "ae6812eb4cd7735a302a8a9dd95cf71f"] ], "08000002", 4 ], "error": null}Notice the same extraNonce1 ("08000002") is returned. The miner can continue using shares it was working on.
Resumption rejected (new session assigned):
{ "id": 2, "result": [ [ ["mining.set_difficulty", "new_subscription_id_1"], ["mining.notify", "new_subscription_id_2"] ], "09000017", 4 ], "error": null}A different extraNonce1 is returned, indicating the old session is gone. The miner must discard any in-progress work and wait for new mining.notify messages.
mining.authorize: Authenticating the Worker
Section titled “mining.authorize: Authenticating the Worker”After subscribing, the miner authenticates one or more workers. This tells the pool which account should receive credit for shares submitted by this connection.
The Request
Section titled “The Request”{ "id": 3, "method": "mining.authorize", "params": [ "myaccount.rig01", "x" ]}Parameter 1: Worker name ("myaccount.rig01")
The format depends on the pool:
| Pool type | Worker name format | Example |
|---|---|---|
| Account-based pool | account.worker | "john.antminer_s19" |
| Wallet-based pool | address.worker | "bc1q...xyz.rig01" |
| Some pools | account (no worker) | "john" |
The part after the dot is the worker name — it is just a label that helps you identify individual machines in the pool’s dashboard. You can name them anything: rig01, shelf3_pos7, garage_unit, whatever makes sense for your setup.
Parameter 2: Password ("x")
Most pools ignore this field entirely. Miners typically send "x", "", or "123". However, some pools repurpose the password field for configuration:
- Difficulty settings:
"d=1024"to request a specific starting difficulty - Payout threshold:
"mc=0.01"for minimum payout - Algorithm selection: on multi-algorithm pools
Success Response
Section titled “Success Response”{ "id": 3, "result": true, "error": null}Simple: result: true means the worker is authorized and can submit shares.
Failure Response
Section titled “Failure Response”{ "id": 3, "result": false, "error": [24, "Unauthorized worker", null]}Error code 24 means “unauthorized.” Common reasons for failure:
- Account does not exist on the pool
- Invalid Bitcoin address (for wallet-based pools)
- Pool requires workers to be created in the web interface first
- Too many workers already connected for this account
Multiple Workers on One Connection
Section titled “Multiple Workers on One Connection”A single TCP connection can have multiple authorized workers:
{"id": 3, "method": "mining.authorize", "params": ["account.rig01", "x"]}{"id": 4, "method": "mining.authorize", "params": ["account.rig02", "x"]}{"id": 5, "method": "mining.authorize", "params": ["account.rig03", "x"]}Each receives an independent response. When submitting shares later via mining.submit, the miner specifies which worker name to credit. This is commonly used by mining proxies that aggregate multiple physical ASICs behind a single pool connection.
The pool tracks hashrate and statistics for each worker independently, even though they share the same extraNonce1 and TCP connection.
Putting It All Together: The Complete Handshake
Section titled “Putting It All Together: The Complete Handshake”Here is a real-world complete handshake sequence as you would capture it with a network analyzer. Each line is one JSON message on the wire:
1. Miner sends mining.configure:
{"id":1,"method":"mining.configure","params":[["version-rolling"],{"version-rolling.mask":"1fffe000","version-rolling.min-bit-count":2}]}2. Pool responds to configure:
{"id":1,"result":{"version-rolling":true,"version-rolling.mask":"1fffe000"},"error":null}3. Miner sends mining.subscribe:
{"id":2,"method":"mining.subscribe","params":["bmminer/2.0.0",null]}4. Pool responds to subscribe:
{"id":2,"result":[[["mining.set_difficulty","1"],["mining.notify","1"]],"08000002",4],"error":null}5. Miner sends mining.authorize:
{"id":3,"method":"mining.authorize","params":["account.worker1","x"]}6. Pool responds to authorize:
{"id":3,"result":true,"error":null}7. Pool pushes initial difficulty:
{"id":null,"method":"mining.set_difficulty","params":[512]}8. Pool pushes first job:
{"id":null,"method":"mining.notify","params":["bf","00000000000000000002...","01000000...","ffffffff...0100000000...","[\"abc123...\",\"def456...\"]","20000000","1705c739","64b3e1a7",true]}The miner is now fully operational and begins hashing.
Edge Cases and Gotchas
Section titled “Edge Cases and Gotchas”What If You Subscribe Before Configure?
Section titled “What If You Subscribe Before Configure?”Some miners skip mining.configure or send it after mining.subscribe. This is technically allowed — mining.configure is an extension, not a requirement. However, if version rolling is needed, the pool will not know to enable it, and the miner may waste hash power by not using the extra nonce space.
Best practice: always send mining.configure first if your hardware supports version rolling.
What If Authorization Fails Mid-Session?
Section titled “What If Authorization Fails Mid-Session?”If the pool deauthorizes a worker mid-session (rare, but possible during pool maintenance), the pool may send:
{ "id": null, "method": "client.reconnect", "params": ["newpool.example.com", 3333, 0]}This tells the miner to disconnect and reconnect to a different address. The parameters are: host, port, and wait time (seconds before reconnecting). Some miners support this; many ignore it.
extraNonce1 Size Varies by Pool
Section titled “extraNonce1 Size Varies by Pool”Different pools use different sizes for extraNonce1:
- Small pools: 2-3 bytes (supporting fewer simultaneous miners)
- Large pools: 4-8 bytes (supporting millions of connections)
The total coinbase nonce space is fixed, so a larger extraNonce1 means less space for extraNonce2, and vice versa. With 8 bytes total nonce space in the coinbase, a pool using 4-byte extraNonce1 leaves 4 bytes for extraNonce2. A pool using 6-byte extraNonce1 leaves only 2 bytes for extraNonce2 (65,536 values), which may not be enough for very fast ASICs.
Unusual User Agent Strings
Section titled “Unusual User Agent Strings”Some pools change their behavior based on the user agent. For example, a pool might automatically enable version rolling if it sees a known ASIC firmware identifier, or might set a different default difficulty for known high-performance miners. While this is pool-specific behavior, it is worth knowing that the user agent string is not just cosmetic.
Summary
Section titled “Summary”The Stratum handshake establishes the foundation for all mining communication:
- mining.configure negotiates protocol extensions (primarily version rolling), giving modern ASICs extra nonce space through the block version field
- mining.subscribe registers the miner with the pool and assigns the critical extraNonce1 and extraNonce2 size parameters that define the miner’s search space
- mining.authorize authenticates one or more workers, linking submitted shares to an account for reward tracking
These three methods run in under 250 milliseconds on a good connection, but the parameters they establish — particularly extraNonce1 and the version rolling mask — govern everything the miner does for the lifetime of the connection.
Next up: mining.notify and mining.submit — the core work loop where jobs arrive, headers are built, and shares are submitted.