Few things break more Modbus maps than a single off-by-one, and it almost always traces back to the difference between the register number a human reads and the address that actually goes on the wire. The famous 40001 is not the number the master sends; it is a naming convention that hides a zero-based offset underneath. This guide untangles the 40001 versus offset confusion, explains why 40001 is really offset 0 read with function code 03, and shows how to line up a vendor's register list with what the master polls.
Modbus Register Addressing (40001 vs 0-Based Offset) in one line: Modbus register addressing has two layers that are easy to confuse. The human-facing register number, like 40001, encodes both the table (the leading 4 means holding register) and a one-based position within it. The address actually placed on the wire is a zero-based offset, so 40001 corresponds to offset 0, 40002 to offset 1, and so on, all read with function code 03. Mixing the two - treating 40001 as if it were offset 40001, or forgetting to subtract one - produces an off-by-one that reads the wrong register or an illegal address error.
The 4xxxx style number is a human convention that packs two pieces of information into one figure. The leading digit names the table - 0 for coils, 1 for discrete inputs, 3 for input registers, 4 for holding registers - and the remaining digits give a one-based position within that table, starting at 1. So 40001 means the first holding register, 40002 the second, and 30001 the first input register. This numbering was designed to be readable for people, letting an engineer glance at 40001 and know it is holding register number one.
The actual Modbus protocol does not send that number. A request carries a function code, which selects the table, and a zero-based address, which gives the position starting from 0. The leading 4 becomes function code 03 for reading holding registers, and the position starts at 0 rather than 1. This is the crux of the whole confusion: the human number is one-based and includes the table digit, while the wire address is zero-based and carries no table digit because the function code already chose the table.
Putting the two together, holding register 40001 is read by sending function code 03 with address 0. Holding register 40002 is function code 03, address 1. The general rule for the 4xxxx range is to drop the leading 4 and subtract one from what remains: 40001 becomes offset 0, 40100 becomes offset 99, 41000 becomes offset 999. The same drop-and-subtract-one applies to the other ranges with their own function codes. Once this translation is internalized, the 40001 notation stops being mysterious and becomes just a friendlier label for a specific function-code-and-offset pair.
The classic error is subtracting one where it is not needed, or failing to subtract it where it is. Some tools and vendor documents present addresses already as zero-based offsets, so a table listing offset 0 for a value is telling you exactly what to put on the wire. Other documents use the 4xxxx human numbering, so a value listed as 40001 must be translated to offset 0 before the master polls it. If a technician takes a number from a document that already uses offsets and subtracts one anyway, every register reads one position low; if they take a 4xxxx number and forget to subtract, every register reads one high.
The confusion is worsened by the fact that both mistakes often still return data rather than an error, because a neighboring register usually exists and answers. Reading offset 1 when you meant offset 0 does not fail loudly - it returns the value of the next register, which may look plausible, especially if adjacent registers hold related values. This makes the off-by-one insidious: the poll succeeds, the number looks like a real measurement, and only careful comparison against a known value reveals that every reading is shifted by one register.
A further trap appears with multi-register values. If a 32-bit value occupies two consecutive registers and the base offset is off by one, the master reads one correct word and one word belonging to a different value, producing a number that is not merely shifted but nonsensical. In that case the off-by-one is easier to catch because the result is obviously wrong rather than plausibly wrong, but the root cause is the same: a mismatch between the register number in the document and the zero-based offset on the wire.
The reliable way to avoid the off-by-one is to first determine which convention a vendor's register list uses before mapping a single value. If the list shows 4xxxx style numbers, translate every entry by dropping the table digit and subtracting one to get the wire offset, and use the function code the table implies. If the list already shows zero-based offsets alongside function codes, use them directly with no subtraction. The single most useful question to ask of any register document is simply whether its numbers are one-based register numbers or zero-based offsets, because the answer determines whether you subtract one.
When a document is ambiguous, a known value is the fastest arbiter. Poll a register whose value you can independently verify - a fixed device identifier, a firmware version, or a measurement you can read on a local display - and see whether it lands at the offset you expect or one away. If the expected value appears one register high or low, you have found the convention mismatch and can shift the whole map accordingly. This empirical check is often quicker and more certain than reasoning about the documentation, especially with a vendor whose numbering is inconsistent across its own pages.
In a cloud SCADA, this alignment is done once per device and then reused for every tag. When Merobix polls a field device over Modbus, each tag is a function code plus a zero-based offset, so building the map correctly means translating the vendor's register numbers into offsets one time and verifying a known value before trusting the rest. Getting that translation right at commissioning is what prevents a whole battery of tags from silently reading one register off - a failure that would otherwise show up much later as measurements that are subtly and consistently wrong.
The 40001 notation is a human convention: the leading 4 names the holding register table and becomes function code 03, while the remaining digits are a one-based position starting at 1. The protocol on the wire uses a zero-based address starting at 0, so the first holding register - written 40001 for people - is offset 0 on the wire. The general rule is to drop the leading 4 and subtract one, so 40001 maps to offset 0.
First check whether the document uses 4xxxx-style register numbers, which are one-based and include a table digit, or plain offsets listed with function codes, which are typically zero-based. If it is still ambiguous, poll a register whose value you can independently verify, such as a device ID or firmware version, and see whether it lands where expected or one register away. Where it lands tells you which convention the list uses.
Because the neighboring register usually exists and answers. Reading offset 1 when you meant offset 0 returns the next register's value rather than failing, and that value can look like a plausible measurement, especially when adjacent registers hold related data. This is what makes the off-by-one so easy to miss - the poll succeeds and the number looks real, so only comparing against a known value reveals that every reading is shifted.
This page references the protocol specifications published by the organizations below. Editions, product capabilities, and documentation change over time - confirm current requirements and specifications directly with the source.
Last reviewed: July 27, 2026. Merobix is not affiliated with, endorsed by, or sponsored by these organizations; their names are used only to identify the standards and products discussed.
Merobix reads your field devices into a cloud SCADA - the real thing behind these terms, live in days from any browser.