We moved this site's database to a new SQL Server, and the first time I tried to connect from my own PC, sqlcmd sat for a few seconds and then printed this:
Sqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : TCP Provider: The wait operation timed out.
Sqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : Login timeout expired.
Sqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : A network-related or instance-specific error
has occurred while establishing a connection to SQL Server. Server is not found or not accessible.
The connection string was right, the password was right and the server was running - the website was using it at that very moment. The problem was one layer below SQL Server: the new host's firewall was silently dropping connections from my IP address. The next day the same error came back, because my home internet connection had been given a new IP. Here is how to tell which layer is failing, and how to fix each one.
The short version: "TCP Provider: The wait operation timed out" (SQL Server error 258) means your computer sent a connection request and never got an answer. Something in the network path - usually a firewall - is dropping it. Run
Test-NetConnection <server> -Port 1433. IfTcpTestSucceededis False, fix the firewall (the server's, the host's or the cloud provider's) before touching SQL Server settings.
What the error actually means
A timeout is different from a refusal. When a port is closed but the machine is reachable, the server answers straight away with "no" and you get an error quickly, such as No connection could be made because the target machine actively refused it (error 10061). A timeout means there was no answer at all. Your packets went out and nothing came back, which is exactly what a firewall does when it drops traffic instead of rejecting it. The Login timeout expired line is just the client giving up after waiting. And error 258 is the Windows code for a wait that timed out, which is why it appears in SQL Server Management Studio and .NET versions of the same failure.
So the error tells you something useful: SQL Server probably never saw your attempt. Changing the password, the database name or the SQL login will not help.
Step 1: test the port, not SQL Server
PowerShell has a built-in test that tries a plain TCP connection to a port:
# Can this machine open a TCP connection to the SQL Server port at all?
Test-NetConnection -ComputerName 203.0.113.10 -Port 1433
# The line that matters:
# TcpTestSucceeded : False -> blocked or nothing reachable; SQL Server never saw the attempt
# TcpTestSucceeded : True -> the network path is open; look at SQL Server itself
This takes SQL Server, drivers, logins and connection strings out of the picture. When I ran it against both servers from the same PC, the answer was immediate:
PS> (Test-NetConnection 203.0.113.10 -Port 1433).TcpTestSucceeded # new server
False
PS> (Test-NetConnection 198.51.100.20 -Port 1433).TcpTestSucceeded # old server, same PC
True
Same computer, same network, same moment: one server reachable and one not. That rules out my PC, my
router and my ISP blocking 1433, and points straight at the new server's side. (On macOS or Linux,
nc -vz 203.0.113.10 1433 does the same job.)
Step 2: what to check when TcpTestSucceeded is False
Work from the outside in. Each of these drops traffic silently, which is what produces the timeout:
- The hosting or cloud firewall. Shared hosting panels, VPS providers and cloud
platforms (Azure network security groups, AWS security groups) usually block 1433 from the internet by
default and let you allow specific IP addresses. This was my case: the host only accepted SQL connections
from listed addresses, and mine was not on the list. Once it was added,
TcpTestSucceededturned True and sqlcmd connected first time. - Windows Firewall on the SQL Server machine. Even with the host's firewall open, Windows Defender Firewall on the server needs an inbound rule for TCP 1433.
- A different port. Named instances such as
SQLEXPRESSuse a dynamic port by default, not 1433. If the instance is not set to a fixed port, testing 1433 will fail even though SQL Server is fine. Check the port in SQL Server Configuration Manager, or connect withserver\instanceand let the SQL Server Browser service (UDP 1434) tell the client the port. - TCP/IP disabled. SQL Server Express installs with TCP/IP turned off. In SQL Server Configuration Manager, enable it under SQL Server Network Configuration, set the port under IP Addresses → IPAll, and restart the SQL Server service. Strictly, this one usually gives a refusal rather than a timeout, but it is on every "allow remote connections" checklist for a reason.
For the Windows Firewall rule, allow your address rather than the whole internet:
# On the SQL Server machine (elevated PowerShell): allow 1433 only from your address
New-NetFirewallRule -DisplayName "SQL Server 1433 from office" `
-Direction Inbound -Protocol TCP -LocalPort 1433 `
-RemoteAddress 203.0.113.45 -Action Allow
Step 3: when it worked yesterday - your IP changed
The day after everything worked, the same timeout came back. Nothing had changed on the server.
Running Test-NetConnection again gave False, and checking my public IP explained it:
# Your public IP - the address the server's firewall sees, not your 192.168.x.x LAN address
(Invoke-RestMethod https://api.ipify.org)
Home and many office broadband connections get a dynamic IP from the ISP, which changes after a router restart or simply every few days. An allow-list with a single address breaks the moment it does. The options, from quickest to most robust:
- Update the allowed address each time it changes - fine if it is rare.
- Allow a small range from your ISP if the host supports CIDR ranges. This trades some security for fewer surprises; keep the range as tight as you can.
- Use a static IP from your ISP, or a VPN with a fixed exit address, and allow only that.
- Do not expose SQL Server at all: connect through an SSH tunnel or a VPN into the server's network, or run your scripts on the server itself. This is what I would recommend for anything beyond a small site.
Whatever you choose, do not solve this by opening 1433 to everyone. A SQL Server listening on the public internet gets password-guessing attempts within hours.
Step 4: when TcpTestSucceeded is True but it still fails
If the port test passes, the network is fine and the error will usually be different:
| Error | What it means |
|---|---|
| Login failed for user (18456) | You reached SQL Server; the login, password or authentication mode is wrong |
| Cannot open database requested by the login | Login is fine; the database name is wrong or the user has no access to it |
| The certificate chain was issued by an authority that is not trusted | Encryption is on by default in newer drivers; install a trusted certificate or set TrustServerCertificate=true for testing |
| Still "wait operation timed out", only on large queries | A query or command timeout rather than a connection timeout; look at the query, not the network |
Two connection-string details are worth checking while you are there: put the port after a comma
(Server=host,1433), not a colon, and give slow networks a longer connect timeout:
Server=203.0.113.10,1433;Database=MyDb;User Id=app_user;Password=<from config>;
TrustServerCertificate=true;Connect Timeout=30;
If you work with sqlcmd a lot, two other errors that cost me time on the same database are 'Scripting variable not defined' and Msg 1934 about QUOTED_IDENTIFIER. And if the connection works locally but the deployed app gets a 500 instead, see ASP.NET Core on Plesk: every error I hit.





Join the conversation
No comments yet — be the first to share what you think.