How to fix Error: tlsv1 alert handshake failure (TLS negotiation failed) in Node.js

Node.jsINTERMEDIATEHIGHUpdated Dec 9, 2025ยท 264 views

This error occurs when Node.js fails to complete a TLS handshake during an HTTPS or secure WebSocket connection. The client and server cannot agree on compatible encryption protocols, cipher suites, or certificate parameters, causing the secure connection to be rejected.

Quick fix

Fixes ERR_TLS_HANDSHAKE_FAILURE

# Test the connection with openssl
openssl s_client -connect example.com:443 -showcerts

# Look at the output:
# - "Verify return code: 0 (ok)" = TLS successful, issue is elsewhere
# - "alert handshake failure" = TLS negotiation failed (this error)
# - "Verify return code: 20" = Certificate validation failed (different error)
  1. Verify the error is actually a TLS negotiation failure
  2. Check which TLS versions the server supports
  3. Update Node.js to a recent LTS version
  4. Explicitly specify TLS version and cipher suites
node.js โ€” error
# Test the connection with openssl
openssl s_client -connect example.com:443 -showcerts
# Look at the output:
# - "Verify return code: 0 (ok)" = TLS successful, issue is elsewhere
# - "alert handshake failure" = TLS negotiation failed (this error)
# - "Verify return code: 20" = Certificate validation failed (different error)
Error: tlsv1 alert handshake failure (TLS negotiation failed)

What this error means

This error indicates that the TLS (Transport Layer Security) handshake between your Node.js client and the server has failed at a critical negotiation stage. During a TLS handshake, the client and server must mutually agree on encryption parameters including: - TLS protocol version (TLSv1.0, TLSv1.2, TLSv1.3, etc.) - Cipher suites for encryption and authentication - Certificate validity and chain verification - Elliptic Curve Diffie-Hellman (ECDH) parameters When these parameters cannot be agreed upon, the server sends an alert message indicating "handshake failure" and terminates the connection. This is a cryptographic negotiation failure, distinct from certificate validation errors.

Typical symptoms

  • HTTPS requests fail with "tlsv1 alert handshake failure" or "alert handshake failure" message
  • WebSocket connections over TLS fail to establish
  • npm install fails when connecting to private registries over HTTPS
  • API calls to certain endpoints fail while others succeed
  • Connection timeout or immediate disconnection without establishing SSL/TLS
  • Error occurs after successful connections in older Node.js versions
  • Certain servers are unreachable while the same request works with curl or other tools

Common causes

  1. TLS protocol version mismatch (e.g., client requires TLSv1.3 but server only supports TLSv1.2)
  2. No overlapping cipher suites between client and server
  3. ECDH curve negotiation failure due to unsupported curves
  4. Node.js version upgrade changed default cipher suites
  5. Server configured with legacy or insecure ciphers no longer supported by Node.js
  6. OpenSSL security level too restrictive for server's cipher configuration
  7. Incompatible elliptic curve selection between client and server
  8. Missing or incompatible Certificate Authority certificates for verification

How to fix "Error: tlsv1 alert handshake failure (TLS negotiation failed)"

1Verify the error is actually a TLS negotiation failure

First, confirm this is a TLS negotiation issue and not a certificate validation error:

bash
# Test the connection with openssl
openssl s_client -connect example.com:443 -showcerts

# Look at the output:
# - "Verify return code: 0 (ok)" = TLS successful, issue is elsewhere
# - "alert handshake failure" = TLS negotiation failed (this error)
# - "Verify return code: 20" = Certificate validation failed (different error)

If you see "alert handshake failure" in the output, the issue is TLS negotiation.

2Check which TLS versions the server supports

Determine the TLS protocol versions available on the server:

bash
# Test TLSv1.3
openssl s_client -connect example.com:443 -tls1_3 -showcerts 2>&1 | grep -E 'Protocol|Ciphers'

# Test TLSv1.2
openssl s_client -connect example.com:443 -tls1_2 -showcerts 2>&1 | grep -E 'Protocol|Ciphers'

# Test TLSv1.0 (if needed)
openssl s_client -connect example.com:443 -tls1 -showcerts 2>&1 | grep -E 'Protocol|Ciphers'

Note which versions work. If only old versions like TLSv1.0 work, you may need special Node.js configuration.

3Update Node.js to a recent LTS version

Older Node.js versions may have different default cipher suites and TLS configurations:

bash
# Check your current version
node --version

# Update using nvm (recommended)
nvm install --lts
nvm use --lts

# Or install from nodejs.org

After updating, test if the connection works. Node.js frequently patches TLS cipher suite defaults for security.

4Explicitly specify TLS version and cipher suites

If updating Node.js doesn't help, explicitly configure TLS parameters in your code:

javascript
const https = require('https');

const options = {
  hostname: 'example.com',
  port: 443,
  path: '/api',
  method: 'GET',
  minVersion: 'TLSv1.2',  // Require at least TLS 1.2
  maxVersion: 'TLSv1.3',  // Allow up to TLS 1.3
  ciphers: 'HIGH:!aNULL:!MD5'  // OpenSSL cipher string
};

https.request(options, (res) => {
  console.log('Connected successfully');
}).on('error', (err) => {
  console.error('TLS error:', err.message);
}).end();

For Axios or other HTTP libraries:

javascript
const axios = require('axios');
const https = require('https');

const agent = new https.Agent({
  minVersion: 'TLSv1.2',
  ciphers: 'HIGH:!aNULL:!MD5'
});

axios.get('https://example.com/api', { httpsAgent: agent });
5Try with --tls-min-v1.0 flag for legacy servers (testing only)

If the server uses very old TLS versions (TLSv1.0 or TLSv1.1), you may need to lower Node.js's minimum supported version:

bash
# For testing purposes only - NOT for production
node --tls-min-v1.0 your-app.js

This allows Node.js to negotiate older TLS versions. However, this is a security risk and should only be used for testing. Better solutions:

1. Upgrade the server to support modern TLS
2. Use a proxy that bridges old and new TLS versions
3. Contact the server administrator to update their configuration

6Check for ECDH curve incompatibility

In some cases, ECDH (Elliptic Curve Diffie-Hellman) curves cause negotiation failures:

bash
# List curves supported by Node.js
node -e "console.log(require('crypto').getCurves())"

# Test OpenSSL available curves
openssl ecparam -list_curves

If the server uses a curve not in Node.js's list, explicitly configure compatible curves:

javascript
const tls = require('tls');
const https = require('https');

const options = {
  hostname: 'example.com',
  port: 443,
  ecdhCurve: 'auto'  // Let Node.js select
};

https.request(options, (res) => {
  // Handle response
}).end();
7Enable TLS debugging to diagnose the exact negotiation failure

Use Node.js built-in TLS debugging to see exactly where negotiation fails:

bash
# Run with TLS debugging enabled
NODE_DEBUG=tls node your-app.js 2>&1 | head -50

# Or with more verbose output
NODE_DEBUG=tls,crypto node your-app.js 2>&1 | head -100

The debug output shows:
- Supported cipher suites from both sides
- Selected cipher after negotiation
- TLS version chosen
- Where the handshake fails

This output can help identify the exact incompatibility.

Advanced notes

Understanding the TLS handshake sequence:

The TLS handshake involves several message exchanges:
1. Client Hello: Client offers supported TLS versions and ciphers
2. Server Hello: Server selects compatible version and cipher
3. Certificate exchange: Server sends certificate for verification
4. Key exchange: Client and server agree on encryption keys
5. Finished: Both sides confirm handshake success

If the server cannot find a compatible cipher or TLS version at step 2, it sends a "handshake failure" alert and terminates.

Cipher suite compatibility:

Node.js links against OpenSSL, which maintains a list of supported ciphers. If your server uses ciphers removed from recent OpenSSL versions for security reasons (like RC4 or DES), you may need:

bash
# Check OpenSSL version and available ciphers
openssl version
openssl ciphers 'ALL'

Modern OpenSSL enforces security levels (0-5, default 2), which can block weak ciphers. You can temporarily lower this for testing:

bash
OPENSSL_CONF=/dev/stdin node -e "..." << 'EOF'
[default]
openssl_conf = openssl_init

[openssl_init]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
MinProtocol = TLSv1.0
CipherString = DEFAULT@SECLEVEL=1
EOF

However, this is dangerous and should only be temporary for diagnosis.

Protocol version transitions:

Starting with Node.js 17, TLSv1.0 and TLSv1.1 support was removed by default. If you need to test with these versions:

javascript
const options = {
  minVersion: 'TLSv1.0',  // Explicitly allow older versions
};

But immediately contact the server administrator to upgrade their TLS configuration.

Docker and OpenSSL configuration:

When running Node.js in containers, ensure the base image has compatible OpenSSL:

dockerfile
# Alpine: May have older OpenSSL
FROM node:18-alpine
RUN apk add --update openssl

# Or use Debian-based for more recent OpenSSL
FROM node:18-bullseye

Debugging with Wireshark:

For detailed packet-level analysis, use Wireshark to capture the TCP handshake and see exactly where TLS negotiation fails. Filter by "tls" to see the TLS handshake messages and alert codes.

Frequently asked questions

What does "ERR_TLS_HANDSHAKE_FAILURE" mean?
js client and the server has failed at a critical negotiation stage. ) - Cipher suites for encryption and authentication - Certificate validity and chain verification - Elliptic Curve Diffie-Hellman (ECDH) parameters When these parameters cannot be agreed upon, the server sends an alert message indicating "handshake failure" and terminates the connection. This is a cryptographic negotiation failure, distinct from certificate validation errors.
How do I fix "ERR_TLS_HANDSHAKE_FAILURE"?
This error occurs when Node.js fails to complete a TLS handshake during an HTTPS or secure WebSocket connection. The client and server cannot agree on compatible encryption protocols, cipher suites, or certificate parameters, causing the secure connection to be rejected.
What causes "ERR_TLS_HANDSHAKE_FAILURE"?
TLS protocol version mismatch (e.g., client requires TLSv1.3 but server only supports TLSv1.2) No overlapping cipher suites between client and server ECDH curve negotiation failure due to unsupported curves
Is the "ERR_TLS_HANDSHAKE_FAILURE" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading