← Back to Blog
TLS 1.0 was introduced in 1999 and is now 27 years old. Chrome, Firefox, Safari, and Edge all disabled TLS 1.0 and TLS 1.1 in 2020–2021. PCI DSS 4.0 (effective March 2025) explicitly prohibits TLS 1.0 and TLS 1.1 for any payment card data environment. If your server still accepts these protocols, you have a compliance problem and a security risk even if no modern browsers connect using them.
TLS 1.1
Released 2006
Deprecated
No significant improvements over 1.0. Disabled with TLS 1.0 in 2020–2021.
TLS 1.2
Released 2008
Supported
Still secure with AEAD ciphers. Minimum requirement for PCI DSS 4.0.
TLS 1.3
Released 2018
Recommended
1-RTT handshake. 0-RTT resumption. Forward secrecy mandatory. Enable alongside TLS 1.2.
PCI DSS 4.0 Requirement 6.4.1: "All web-facing applications must use only trusted protocols (TLS 1.2 or higher)." Any system handling cardholder data that accepts TLS 1.0 or 1.1 is non-compliant as of March 31, 2025.
Step 1: Test If Your Server Still Accepts TLS 1.0 or 1.1
# Test TLS 1.0 (should fail/close connection on properly configured servers):
openssl s_client -connect yourdomain.com:443 -tls1 2>&1 | head -5
# Test TLS 1.1:
openssl s_client -connect yourdomain.com:443 -tls1_1 2>&1 | head -5
# Test TLS 1.2 (should succeed):
openssl s_client -connect yourdomain.com:443 -tls1_2 2>&1 | head -5
# Test TLS 1.3 (should succeed on modern servers):
openssl s_client -connect yourdomain.com:443 -tls1_3 2>&1 | head -5
Interpreting the output:
# TLS 1.0 ACCEPTED (bad — fix required):
SSL handshake has read ... bytes
New, TLSv1, Cipher is ECDHE-RSA-AES256-SHA
← TLS 1.0 was negotiated — your server still accepts it
# TLS 1.0 REJECTED (correct):
no peer certificate available
140226956462528:error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version
← Server rejected TLS 1.0 — correctly configured
# nmap for a comprehensive scan:
$ nmap --script ssl-enum-ciphers -p 443 yourdomain.com
443/tcp open https
| ssl-enum-ciphers:
| TLSv1.2:
| ciphers: ECDHE-RSA-AES256-GCM-SHA384
| TLSv1.3:
| ciphers: TLS_AES_256_GCM_SHA384
|_ least strength: A ← no TLS 1.0/1.1 shown = correct
Step 2: Disable TLS 1.0 and 1.1 in Apache
# Check current Apache version and OpenSSL version:
apache2 -v
openssl version
# Edit your SSL VirtualHost config (typically in /etc/apache2/sites-available/):
# Find the SSLProtocol line (or add it inside VirtualHost *:443):
# WRONG — still allows TLS 1.0 and 1.1:
SSLProtocol all -SSLv3
# CORRECT — allow only TLS 1.2 and TLS 1.3:
SSLProtocol -all +TLSv1.2 +TLSv1.3
# ALSO update cipher suites to remove RC4 and weak ciphers:
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
SSLHonorCipherOrder off
# Apply changes:
sudo apache2ctl configtest # verify syntax before reloading
sudo systemctl reload apache2
Step 3: Disable TLS 1.0 and 1.1 in Nginx
# Edit your server block (typically /etc/nginx/sites-available/yourdomain.conf):
# WRONG:
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
# CORRECT:
ssl_protocols TLSv1.2 TLSv1.3;
# Add modern cipher suites:
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# Test and reload:
sudo nginx -t # test config
sudo nginx -s reload
Step 4: Update OpenSSL if Needed
# Check if your OpenSSL version supports TLS 1.3:
openssl version
# OpenSSL 3.x ← TLS 1.3 supported
# OpenSSL 1.0.x ← TLS 1.3 NOT supported, upgrade required
# Update OpenSSL on Ubuntu/Debian:
sudo apt update && sudo apt upgrade openssl libssl-dev
# After upgrading OpenSSL, also restart Apache/Nginx:
sudo systemctl restart apache2
# or:
sudo systemctl restart nginx
Step 5: Verify the Changes
# Test all protocol versions after the fix:
echo "=== TLS 1.0 (should fail) ===" && \
openssl s_client -connect yourdomain.com:443 -tls1 2>&1 | grep -E "Protocol|error"
echo "=== TLS 1.1 (should fail) ===" && \
openssl s_client -connect yourdomain.com:443 -tls1_1 2>&1 | grep -E "Protocol|error"
echo "=== TLS 1.2 (should succeed) ===" && \
openssl s_client -connect yourdomain.com:443 -tls1_2 2>&1 | grep -E "Protocol|Cipher"
echo "=== TLS 1.3 (should succeed) ===" && \
openssl s_client -connect yourdomain.com:443 -tls1_3 2>&1 | grep -E "Protocol|Cipher"
Impact on Legacy Clients
The question everyone asks before disabling TLS 1.0: "Will this break anyone?" In 2026, the answer is almost certainly no for web traffic, but check your logs:
# Apache — find requests using TLS 1.0 or 1.1 in access logs:
grep "TLSv1\"" /var/log/apache2/access.log | wc -l
grep "TLSv1.1\"" /var/log/apache2/access.log | wc -l
# Apache log format must include %{SSL_PROTOCOL}x:
# LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %{SSL_PROTOCOL}x %{SSL_CIPHER}x" ssl_combined
# CustomLog ${APACHE_LOG_DIR}/access.log ssl_combined
If you see non-zero counts, inspect the User-Agent to determine if these are real users or monitoring bots. Most monitoring tools from before 2021 will show up here — update them to use TLS 1.2.
Disabling TLS 1.0 and 1.1 on Windows Server (IIS)
Windows Server 2012+
IIS / Schannel
Unlike Apache and Nginx where TLS versions are configured in a text file, Windows controls TLS protocol support at the OS level via the Schannel registry keys. Changes apply to IIS and all other Schannel-based applications system-wide.
Option A: PowerShell Script (Recommended)
# Run in elevated PowerShell — disables TLS 1.0 and 1.1, enables TLS 1.2 and 1.3
$protocols = @{
"TLS 1.0" = $false
"TLS 1.1" = $false
"TLS 1.2" = $true
"TLS 1.3" = $true # Windows Server 2022 / Windows 11+ only
}
foreach ($protocol in $protocols.GetEnumerator()) {
$name = $protocol.Key
$enable = $protocol.Value
$value = if ($enable) { 1 } else { 0 }
$regBase = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$name"
# Server key
New-Item -Path "$regBase\Server" -Force | Out-Null
New-ItemProperty -Path "$regBase\Server" -Name "Enabled" -Value $value -PropertyType DWORD -Force | Out-Null
New-ItemProperty -Path "$regBase\Server" -Name "DisabledByDefault" -Value ([int]!$enable) -PropertyType DWORD -Force | Out-Null
# Client key
New-Item -Path "$regBase\Client" -Force | Out-Null
New-ItemProperty -Path "$regBase\Client" -Name "Enabled" -Value $value -PropertyType DWORD -Force | Out-Null
New-ItemProperty -Path "$regBase\Client" -Name "DisabledByDefault" -Value ([int]!$enable) -PropertyType DWORD -Force | Out-Null
Write-Host "$name : $(if($enable){'Enabled'}else{'Disabled'})"
}
Write-Host "Reboot required to apply changes."
Option B: IIS Crypto (GUI Tool)
IIS Crypto (free, from Nartac Software) provides a GUI for managing all Schannel protocols and cipher suites. The "Best Practices" button applies Microsoft's recommended settings in one click — disabling TLS 1.0/1.1 and weak ciphers.
:: After running IIS Crypto and applying settings:
:: A reboot is required for Schannel changes to take effect.
shutdown /r /t 60 /c "Applying TLS protocol changes"
Verify TLS Versions After Reboot
# Verify TLS 1.0 is disabled from PowerShell
$path10 = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server"
$enabled = (Get-ItemProperty -Path $path10 -Name "Enabled" -ErrorAction SilentlyContinue).Enabled
Write-Host "TLS 1.0 Server Enabled: $enabled" # Should be 0
# Or test remotely with OpenSSL (install via winget install ShiningLight.OpenSSL)
openssl s_client -connect yourdomain.com:443 -tls1 2>&1 | Select-String "Protocol|alert"
# If TLS 1.0 is disabled, output will show: "alert protocol version" or connection failure
A reboot is required: Schannel registry changes do not take effect until the server is rebooted — unlike Apache/Nginx which only need a service reload. Plan your maintenance window accordingly.
Disabling TLS 1.0 on macOS (Homebrew)
macOS
Homebrew Apache / Nginx
On macOS with Homebrew Apache or Nginx, TLS version control uses the same directives as Linux — only the config file paths differ.
# Homebrew Apache — edit /opt/homebrew/etc/httpd/extra/httpd-ssl.conf
# Find the SSLProtocol line and update it:
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
# Homebrew Nginx — edit /opt/homebrew/etc/nginx/nginx.conf
# Inside the http {} or server {} block:
ssl_protocols TLSv1.2 TLSv1.3;
# Test and reload
httpd -t && brew services restart httpd # Apache
nginx -t && brew services restart nginx # Nginx
# Verify TLS 1.0 is blocked
openssl s_client -connect localhost:443 -tls1 2>&1 | grep -E "Protocol|alert"
# Expected: "alert protocol version" = TLS 1.0 correctly rejected
macOS system TLS (used by Safari, curl, and native apps) is controlled by Apple and does not support TLS 1.0 or 1.1 as of macOS 10.15 Catalina. You do not need to disable them — they are already off by default.
Check which TLS versions your server supports
Our SSL checker shows all accepted protocol versions and flags TLS 1.0 and 1.1 as security issues.