SSN format is one of those small pieces of knowledge that quietly decides whether a form validation rule is correct. The number is nine digits long, it is conventionally written in three groups, and a few of the possible combinations within it are never issued to anyone — facts that are simple to state and surprisingly easy to get wrong when they are encoded into a validation routine.
This article covers the structure of the number, the ranges that are held back, what the digits stopped meaning in 2011, and why the number never was and still is not proof of identity.
The shape of the number
The nine digits are read as three blocks: three digits, then two, then four. Written out, the blocks are usually separated by hyphens, though the hyphens are a formatting convention rather than part of the number, and plenty of systems store and print it as a single unbroken run.
Each block has a name. The first three digits are the area number, the middle two are the group number, and the last four are the serial number. Knowing the names is useful mainly because the reserved values are defined per block.
Treat the whole thing as text. A leading zero inside a block is perfectly normal and completely legal, and any storage decision that turns the value into an integer will silently destroy it — a failure mode that has broken a great many forms over the years.
Which ranges are never issued?
The administration that issues the number has publicly stated that certain values are not used. In the area block, the all-zero value is not issued, the value made of three sixes is not issued, and the block of values from nine hundred upward is not issued. In the group block, the all-zero pair is not issued. In the serial block, the all-zero set is not issued.
The pattern is worth noticing: in each case the withheld value is one of the degenerate ones, the extreme low end or a deliberately excluded special. That is a useful property for anyone writing a validator, because it means a handful of cheap range checks catch a whole class of obviously fabricated or mistyped numbers.
It does not mean the checks are sufficient. Passing them establishes only that a number is not in a known-impossible range; it says nothing about whether the number was ever issued, and nothing at all about who holds it.
Does the first block tell you where someone was born?
It used to correlate with the state where the number was applied for, and the folklore that grew around that correlation outlived the actual practice by decades. Since 2011 the numbers have been assigned on a randomised basis, so the digits no longer encode a place of application and never encoded a date of birth.
The practical consequence is that any rule inferring a region, a birth year or an issuance date from the first digits is now wrong, and was already unreliable before the change because the mapping was regional rather than personal. Validation code written from a table of state prefixes is the most common way this mistake reaches production.
Is an SSN an identity document?
No. It is a number issued for a specific administrative purpose, and it is not a general-purpose national identity card, not proof of citizenship, and not evidence of who someone is. Presenting a number does not establish a person’s identity, and a system that treats the number alone as sufficient proof is relying on a secret that has never been secret — the number is asked for by employers, landlords, clinics and utility companies, so it is widely recorded and widely leaked.
That is the honest framing of the whole topic, and it is the reason this number is such a poor fit for testing that involves real people. A properly shaped value is fine for checking that a form accepts nine digits in three groups. A real one in a test database is a liability: it belongs to somebody, it cannot be un-leaked, and no amount of access control on a staging environment makes that copy safe.
How should a form treat the number?
Collect it only when there is a real reason, store it in as few places as the task allows, mask it in every interface that does not strictly need the full value, and never print it into a log line. Those are data-handling choices, and they apply whether the system is a payroll platform or a side project.
On the validation side, resist the urge to be clever. Rejecting a value because the first three digits are not in a list of recognised prefixes will reject legitimate numbers, because the list of valid prefixes is not a fixed geography and the all-zero, all-sixes and high ranges are the only values with a public rule. Check the shape, check the reserved ranges, and leave the rest alone.
Teams that need to exercise the field without touching anyone’s real number use a synthetic value. Records generated by the identity and test data generator fall in that category: they satisfy the format and avoid the reserved ranges, and they are made up for testing, not usable to impersonate anyone or to satisfy any check that verifies the number against an issuing record.
What should a validator check, and in what order?
Six checks cover almost everything, and their order matters only because the cheapest should run first.
- The value is present and, once formatting characters are removed, consists of digits only.
- After removing separators, it is exactly nine digits long.
- The area block is not all zeros, not the excluded three-sixes value, and below nine hundred.
- The group block is not all zeros.
- The serial block is not all zeros.
- The field is stored and compared as text, so that leading zeros survive.
Nothing on that list is a check that the number corresponds to a person. If a process needs that guarantee, it needs a source of truth outside the form, and the form cannot supply it.
For developers: what belongs in the validation rule
Write the rule as format plus reserved ranges and stop there. A comment stating that the digits carry no geographic meaning is worth more than an extra branch, because the next person to edit the file will otherwise reintroduce the prefix table they remember from an old project.
Keep the fixture honest, too. Use a generated value, label the row as synthetic in the dataset itself so a leaked screenshot explains itself, and make sure nobody has quietly pasted a real number in as a convenience. The number is not a general identifier, and a test suite that treats it as one teaches the wrong lesson to everyone who reads it. Records built for testing are exactly that — testing artefacts that must never stand in for a real person’s identity or be presented anywhere as one.
Next steps
Open your validation routine and delete any branch that infers a location or a year from the first three digits; that change alone removes a recurring source of false rejections. Then generate a batch of US records in the identity generator and run them through the field, including one whose serial block is deliberately all zeros to confirm the reserved-range check actually fires. For the wider picture of how identification numbers differ between countries, the guide to national ID length is the natural follow-up.