Short answer: the client lists the TLS versions it supports in the supported_versions extension, most preferred first. The server selects one version from that list (subject to its own policy) and reports the choice in its ServerHello or HelloRetryRequest. For TLS 1.3, the existing version field keeps a compatibility value, while the extension carries the real selection.
Why TLS 1.3 moved negotiation into an extension
Older TLS handshakes used a version field in ClientHello and ServerHello. Advancing that field to a value unknown to deployed middleboxes risked those devices rejecting or mishandling otherwise valid traffic. TLS 1.3 therefore keeps the old field values and puts version offers and selections in a new extension.
RFC 9846, which supersedes the earlier TLS 1.3 specification, states: “The “supported_versions” extension is used by the client to indicate which versions of TLS it supports and by the server to indicate which version it is using.”
This design lets a TLS 1.3-capable client remain intelligible to older peers while giving newer peers an unambiguous negotiation mechanism. It does not make obsolete protocol versions safe by default: the versions a deployment permits remain a security and interoperability policy decision.
#1 Best Overall
What the client sends
The preference-ordered list
In ClientHello, supported_versions contains a vector of two-byte version values. The client orders the list with its preferred version first. In the TLS 1.3 specification, an implementation sends this extension with every TLS version it is prepared to negotiate; TLS 1.3 support means including 0x0304. Older versions should appear only when the implementation is actually willing to use them. The vector length is 2 to 254 bytes, so it contains at least one version and can carry multiple offers.
Ordering expresses preference, not a promise that the server will choose the first entry. The server is limited to versions that both appear in the list and satisfy its configuration, implementation, and security policy.
The compatibility field is not authoritative when the extension is present
A TLS 1.3 ClientHello sets legacy_version to 0x0303, the value historically associated with TLS 1.2. That value exists for compatibility. When supported_versions is present, the server must use the extension for version negotiation, ignore unknown values in its list, and not use legacy_version to decide the negotiated version.
How the server chooses and signals a version
Selection rules
The server selects a mutually supported version from the client’s offered list. “Mutually supported” includes the server’s local policy: a server may decline a version it implements but has disabled. Unknown version values in the client’s list are ignored, allowing newer clients to advertise values an older server does not understand.
If no offered version is acceptable, the handshake cannot proceed. The exact alert or failure presentation depends on the protocol state and implementation; a client should not assume that retrying with a modified list is a safe fallback.
TLS 1.3 selection
When selecting TLS 1.3, the server sends:
ServerHello.legacy_version = 0x0303; and- a
supported_versionsextension containing the selected value0x0304.
A TLS 1.3 client must inspect this extension before processing the rest of ServerHello. If the selected value was not offered, or is below TLS 1.3 in this TLS 1.3 response-extension context, the client aborts with illegal_parameter.
The extension can also appear in a HelloRetryRequest. In that message it carries one selected version, just as the server’s final response does.
Selection of an earlier version
If the server selects a pre-TLS-1.3 version, it puts that version in ServerHello.version and omits supported_versions. The client then follows the rules for the selected older protocol version.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Two negotiation paths compared
| ClientHello condition | Authoritative value | Server encoding | Compatibility behavior |
|---|---|---|---|
supported_versions present |
The offered extension list; legacy_version is not used for selection |
For TLS 1.3, legacy_version=0x0303 plus extension value 0x0304. For an older selected version, the server uses the older-version field and omits the extension. |
Unknown offers are ignored; the selected version must be one the client offered. |
supported_versions absent |
The legacy version-negotiation rules | ServerHello.version carries the selected version; no selection extension is sent. |
A compliant server supporting TLS 1.2 negotiates TLS 1.2 or earlier under the older rules, even if a legacy field appears to contain a later-looking value. It may abort when the legacy offer is unacceptable. |
A concrete TLS 1.3 example
Suppose a client is willing to use TLS 1.3 and TLS 1.2, preferring TLS 1.3. Its relevant fields are conceptually:
ClientHello legacy_version: 0x0303 supported_versions: [0x0304, 0x0303]
A TLS 1.3 server can answer:
ServerHello legacy_version: 0x0303 supported_versions: [0x0304]
The repeated 0x0303 values in the legacy fields do not mean TLS 1.2 was negotiated. The extension’s 0x0304 selection is authoritative.
Rank #3
An older server that cannot negotiate TLS 1.3 can instead send a TLS 1.2 ServerHello with version = 0x0303 and no supported_versions. The client may continue only if TLS 1.2 is enabled and acceptable in its policy.
What happens when the extension is missing
The absence of supported_versions is a separate protocol path, not an implicit TLS 1.3 offer. A server that supports TLS 1.2 follows the pre-TLS-1.3 rules and negotiates TLS 1.2 or an earlier version. The server can abort if the legacy ClientHello version is unacceptable. A TLS 1.3 client therefore includes the extension when it wants TLS 1.3 considered.
Free tools Windows power users keep installed
One-click scans. No signup required.
Do not infer support from the numeric appearance of legacy_version. In a TLS 1.3 handshake, 0x0303 is deliberately retained as a compatibility value.
Downgrade protection and fallback decisions
TLS 1.3’s design includes downgrade defenses for negotiation between newer peers. RFC 9846 explains that a middlebox passing traffic without terminating TLS should not be able to influence version negotiation between newer endpoints. That protection depends on the endpoints and their configurations; it is not a blanket guarantee for every legacy combination.
Deployments often update at different speeds, so retaining older versions can improve interoperability. That is a deliberate policy trade-off, not a protocol requirement. Disable versions your security baseline does not permit, and do not treat the presence of a newer offer as evidence that the peer will select it.
RFC 8446 warns against repeated compatibility attempts for broken peers. Retrying a handshake with progressively weaker settings can create a downgrade opportunity. Prefer one policy-defined offer and fail clearly when the peer cannot meet it.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallHow to read a capture or implementation log
- Find
ClientHello.supported_versions. Record every value and its order. - Confirm whether
legacy_versionis merely0x0303; do not use it to infer a TLS 1.2 negotiation when the extension exists. - Inspect
ServerHelloorHelloRetryRequest. A TLS 1.3 response has a one-valuesupported_versionsextension. - Verify that the selected value was offered by the client and is allowed by local policy.
- If the server omits the extension, interpret
ServerHello.versionusing the older negotiation path.
A failed connection cannot be diagnosed from the extension alone. You need the handshake capture, both peers’ implementation and version information, and their enabled-version configuration.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Common mistakes and their fixes
Reading 0x0303 as proof of TLS 1.2
In a TLS 1.3 exchange, both sides can show 0x0303 in legacy fields. Check the server’s supported_versions extension; 0x0304 there means TLS 1.3.
Assuming the first offered version must win
The list is preference ordered, but the server chooses among versions it supports and permits. Check server policy and the actual response.
Accepting a server-selected value that was not offered
A client must abort rather than silently continue. For a TLS 1.3 response-extension violation, the specified alert is illegal_parameter.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsBest Value
- Used Book in Good Condition
Retrying with weaker settings after a failure
Automatic downgrade retries can be attacked. Make fallback explicit, bounded by policy, and observable instead of silently removing modern versions.
Assuming an absent extension means “no TLS 1.3 support” in every case
It means this handshake is using the legacy negotiation path. An older peer will not negotiate TLS 1.3 through that path, but the correct diagnosis still requires identifying the peer and its configuration.
Or skip the browser setup
If you need a clean visual record of TLS documentation or an internal protocol page, ScreenshotNeo can capture a URL with one request instead of configuring a browser. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be disabled. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server provides take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.
Example (see the ScreenshotNeo documentation):
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://screenshotneo.com/docs/ -o shot.webp
The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Frequently Asked Questions
What does 0x0304 represent?
It is the protocol value identifying TLS 1.3 in the supported_versions extension.
Can a server select a version the client did not list?
No. When supported_versions is present, the server selects only an offered, acceptable version; a TLS 1.3 client aborts if the response selects an unoffered value.
Why is TLS 1.2’s value still visible in a TLS 1.3 handshake?
TLS 1.3 retains 0x0303 in legacy fields for compatibility with middleboxes. The extension, not that field, identifies the TLS 1.3 selection.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Recommended Free Tools

