Connecting to SQL Server named instance from Linux using pyodbc - python

I'm currently trying to connect to a SQL Server (that I don't have visibility into, but have credentials for) using PyODBC. The code that I have works on my Windows desktop, but does not work when moved onto my RedHat Linux machine. I need it on Linux in support of a project.
Here's what I have:
server = 'tcp:myserver\inst1'
database = 'mydatabase'
username = 'myusername'
password = 'mypassword'
cnxn = pyodbc.connect('DRIVER={ODBC Driver 13 for SQL Server};SERVER=' + server + ';DATABASE=' + database + ';UID=' + username + ';PWD=' + password)
And here is the error I'm getting:
pyodbc.OperationalError: ('HYT00', u'[HYT00] [unixODBC][Microsoft][ODBC Driver 13 for SQL Server]Login timeout expired (0) (SQLDriverConnect)')
The one difference between the Windows version and Linux version is the driver portion. Windows uses '{SQL Server}' while the Linux version uses '{ODBC Driver 13 for SQL Server}'.
In my /etc/odbcinst.ini file, I have the following information:
[ODBC Driver 13 for SQL Server]
Description=Microsoft ODBC Driver 13 for SQL Server
Driver=/opt/microsoft/msodbcsql/lib64/libmsodbcsql-13.1.so.9.1
UsageCount=1
Anyone have any suggestions?

Unlike the Windows versions of Microsoft's ODBC Drivers for SQL Server, the Linux versions of those drivers are unable to resolve SQL Server instance names. So on a Windows client we can use the following (provided that the SQL Browser service is running on the server)
cnxn = pyodbc.connect(
"Driver=ODBC Driver 17 for SQL Server;"
r"Server=myserver\SQLEXPRESS;"
# and so on
)
but that won't work on Linux. However we can use the sqlserverport module (which I maintain) to retrieve the port number from the SQL Browser service:
import pyodbc
import sqlserverport
servername = "myserver"
serverspec = f"{servername},{sqlserverport.lookup(servername, 'SQLEXPRESS')}"
conn = pyodbc.connect(
"Driver=ODBC Driver 17 for SQL Server;"
f"Server={serverspec};"
# and so on

Use the driver path instead of the driver name. In your example take the full /opt/microsoft/msodbcsql/lib64/libmsodbcsql-13.1.so.9.1

use IP address and port number instead of name/instancename.
execute this query to have the real port number:
SELECT DISTINCT local_net_address, local_tcp_port FROM sys.dm_exec_connections
and then datasrc=N'192.168.1.112,61423'

Related

OperationalError when trying to connect to SQL Server database using pyodbc

I'm trying to connect to a SQL server database using pyodbc in Python 3. But I get an error when I'm trying to establish the connection.
I do something like this:
import pyodbc
conn = pyodbc.connect('Driver={ODBC Driver 18 for SQL Server};Server=192.168.2.250;Database=DB;UID=username;PWD=password;')
And I get this:
OperationalError: ('08001', '[08001] [Microsoft][ODBC Driver 18 for SQL Server]SSL Provider: [error:1425F102:SSL routines:ssl_choose_client_version:unsupported protocol][error:140B40C7:SSL routines:SSL_do_handshake:peer did not return a certificate] (-1) (SQLDriverConnect)')
Does anybody know how to solve this? The database is not my own, so I hope there is a solution that doesn't require changing any settings there.
I'm running Ubuntu within the Windows Subsystem for Linux.
There is a breaking change in ODBC Driver 18 for SQL Server
Similar to the HTTP to HTTPS default changes made in web browsers a few years back (and the security reasons for them), we are changing the default value of the Encrypt connection option from no to yes/mandatory.
ODBC Driver 18.0 for SQL Server Released
So this
conn = pyodbc.connect('Driver={ODBC Driver 18 for SQL Server};Server=192.168.2.250;Database=DB;UID=username;PWD=password;')
is the same as
conn = pyodbc.connect('Driver={ODBC Driver 18 for SQL Server};Server=192.168.2.250;Database=DB;UID=username;PWD=password;Encrypt=yes')
If you don't want an encrypted connection you must opt out:
conn = pyodbc.connect('Driver={ODBC Driver 18 for SQL Server};Server=192.168.2.250;Database=DB;UID=username;PWD=password;Encrypt=no')
We also changed the behavior of TrustServerCertificate to not be tied to the Encrypt setting
So if your server is using a self-signed certificate, you also must opt out of certificate validation. so
conn = pyodbc.connect('Driver={ODBC Driver 18 for SQL Server};Server=192.168.2.250;Database=DB;UID=username;PWD=password;Encrypt=no;TrustServerCertificate=yes')
I ended up taking my script out of WSL. Running the same command (with David's additions or ODBC Driver 17 for SQL Server instead of 18) under Windows works without issues in my case.

Pyodbc timeout while connecting to SQL Server on Linux

During connection (not query execution), following problem with timeout occurs:
('HYT00', '[HYT00] [Microsoft][ODBC Driver 17 for SQL Server]Login timeout expired (0) (SQLDriverConnect)')
Code:
import pyodbc
import pandas as pd
cnxn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER='+server+';DATABASE='+database+';UID='+username+';PWD='+ password)
cursor = cnxn.cursor()
DF = pd.read_sql_query(query, cnxn)
This problem doesn't exist on Windows. In both cases I am using Forticlient VPN. Other networking works fine. Current configuration: Ubuntu 20.04 current patch, Windows 10 current patch. Driver was installed with official Microsoft's instruction:
https://learn.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15

Connecting to Azure SQL Server via Jupyter (issues!)

I'm trying to connect to an Azure SQL Server instance from a laptop with Jupyter installed. Fairly new at this but having issues which are probably simple to resolve.
I've installed 64bit Python 3.7, Jupyter and AMD64 v17 pyodbc via pip. However when I'm trying to connect via Jupyter I just get either connection or driver issues, not quite sure.
Below is the code I'm trying to run to connect and return a simple top 10 rows query.
import pyodbc
server = 'xxxsqlserver.database.windows.net'
database = 'xxx.dbo.table'
username = 'user'
password = 'password'
driver='{ODBC Driver 17 for SQL Server}'
cnxn = pyodbc.connect('DRIVER='+driver+';SERVER='+server+';PORT=1433;DATABASE='+database+';UID='+username+';PWD='+ password)
cursor = cnxn.cursor()
cursor.execute("SELECT TOP 10 * FROM xxx.dbo.table")
row = cursor.fetchone()
while row:
print (str(row[0]) + " " + str(row[1]))
row = cursor.fetchone()
Below is the error message I get:
InterfaceError Traceback (most recent call
last) in
5 password = 'password'
6 driver='{ODBC Driver 17 for SQL Server}'
----> 7 cnxn = pyodbc.connect('DRIVER='+driver+';SERVER='+server+';PORT=1433;DATABASE='+database+';UID='+username+';PWD='+
password)
8 cursor = cnxn.cursor()
9 cursor.execute("SELECT TOP 10 * FROM xxx.dbo.table")
InterfaceError: ('IM002', '[IM002] [Microsoft][ODBC Driver Manager]
Data source name not found and no default driver specified (0)
(SQLDriverConnect)')
If I change the driver to 13 I get a different error
InterfaceError: ('28000', '[28000] [Microsoft][ODBC Driver 13 for SQL
Server][SQL Server]Login failed for user \'user\'. (18456)
(SQLDriverConnect); [28000] [Microsoft][ODBC Driver 13 for SQL
Server][SQL Server]Cannot open database "xxx.dbo.table" requested by
the login. The login failed. (4060); [28000] [Microsoft][ODBC Driver
13 for SQL Server]Invalid connection string attribute (0); [28000]
[Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Login failed for
user \'user\'. (18456); [28000] [Microsoft][ODBC Driver 13 for SQL
Server][SQL Server]Cannot open database "xxx.dbo.table" requested by
the login. The login failed. (4060); [28000] [Microsoft][ODBC Driver
13 for SQL Server]Invalid connection string attribute (0)')
Feels like the driver isn't doing something quite right or I've got a misalignment somewhere. Note I didn't install any version 13 drivers but do have SSMS installed which put some in, and this connects to the Azure platform just fine.
Any ideas?
Thanks.
Hi there from the looks of things, this may be because your ODBC drivers are not installed properly. It is mostly likely because your are not formatting the string properly. So, here is a comprehensive list of what you need to do:
Install the correct ODBC drivers to connect with SQLServer
This depends on your operating system of course, if you have MacOS, you can go ahead and install it using homebrew like so:
brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release
brew update
brew install msodbcsql17 mssql-tools
If you do not know what homebrew is, please take a look at the homebrew official website. If this is not your operating system, then take a look at OS specific instructions in this guide.
Once you have done this, make sure to follow the instructions at the end of the installation, where they tell you what changes you need to make to your dotfiles in order to get ODBC working properly.
Make sure to get the connection string properly. The connection string is located in the "Connection Strings" section of your SQLServer database, and under ODBC:
Once you have the connection string, use fstrings or the .format() function on a string to replace the section of the string that says Pwd={your_password_here}
This should do the trick. However, if it does not then you need to check whether you have the correct username, password and table. If you are sure that they are correct, then you might want to contact Support, since they might have changed the requirements for drivers to be a specific version for your database.
I've also encountered the same error while connecting to Azure SQL database.
The error disappeared once the driver name was changed from DRIVER={ODBC Driver 17 for SQL Server} to DRIVER={SQL Server}, for example:
import pyodbc
server = '<sql-server-name>.database.windows.net'
database = '<database>'
username = '<username>'
password = '<password>'
driver='{SQL Server}'
cnxn = pyodbc.connect('DRIVER='+driver+';SERVER='+server+';PORT=1433;DATABASE='+database+';UID='+username+';PWD='+ password)
cursor = cnxn.cursor()
cursor.execute("SELECT TOP 10 * FROM dbo.allOrders")
row = cursor.fetchone()
while row:
print (str(row[0]) + " " + str(row[1]))
row = cursor.fetchone()

pyodbc.connect - works from one computer but not another

I have been running Python script using my desktop at work that successfully connects to a remote desktop server and outputs data in SQL via pyodbc.connect.
I am looking to migrate this code to a separate remote desktop PC recently installed at work and I get the following error:
InterfaceError: ('IM002', '[IM002] [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified (0) (SQLDriverConnect)')
The code I am using is:
cnxn = pyodbc.connect("Driver={SQL Server Native Client 11.0};"
"Server=AUBAMTRAS01-DEV;"
"Database=ForwardTrading;"
"Username=xxxxxxxx;"
"Password=yyyyyyyy;"
"Trusted_Connection=yes;")
cursor = cnxn.cursor()
cursor.execute('SELECT distinct(Commodity) from ForwardCurvesOilAndGas')
for row in cursor:
print('row = %r' % (row,))
Data source name not found and no default driver specified
This means you need to install the SQLDriverConnect driver on your second machine.
SOLVED - Driver required was 'SQL Server' not 'SQL Server Native Client 11.0'

Remote connection to MS SQL - Error using pyodbc vs success using SQL Server Management Studio

I have a MS SQL database in the same network but in other computer.
Using the SQL Server Management Studio (SSMS) Express, I can find the database and connect without problems.
But when I use pyodbc to connect to the same server using:
import pyodbc
server = r"xxxER\xxxSQLSERV"
db = "xxxDB"
user = "xxx"
password = "xxxx"
conn = pyodbc.connect('DRIVER={SQL Server};SERVER='+server + ';DATABASE=' + db +';UID=' + user + ';PWD=' + password)
I get following error:
pyodbc.OperationalError: ('HYT00', '[HYT00] [Microsoft][ODBC SQL Server Driver]Login timeout expired (0) (SQLDriverConnect)')
OBS: I guess that the server string should be right, since if I change it I get always the following error:
pyodbc.Error: ('08001', '[08001] [Microsoft][ODBC SQL Server Driver][DBNETLIB]SQL Server does not exist or access denied. (17) (SQLDriverConnect); [01000] [Microsoft][ODBC SQL Server Driver][DBNETLIB]ConnectionOpen (Connect()). (53)')
Here the image showing success while using SQL Server Studio Express to connect remotely.
Try specifying the port:
import pyodbc
server = r"xxxER\xxxSQLSERV"
db = "xxxDB"
user = "xxx"
password = "xxxx"
port = "1433"
conn = pyodbc.connect('DRIVER={SQL Server};SERVER=' + server + ';PORT=' + port + ';DATABASE=' + db +';UID=' + user + ';PWD=' + password)
If you're still having issues, try using the IP or FQDN of the server.
"But why ...?"
For those interested in why SQL Server Management Studio (SSMS) can connect to servername\instance while other applications (like our pyodbc apps) cannot, it's because SSMS keeps an MRU (Most Recently Used) list of port numbers in the Windows registry at
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Client\SuperSocketNetLib\LastConnect
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\MSSQLServer\Client\SuperSocketNetLib\LastConnect
Each MRU entry (registry value) looks something like this:
Name: PANORAMA\SQLEXPRESS
Type: REG_SZ
Data: -1006030326:tcp:PANORAMA,52865
Once SSMS has successfully connected by instance name via the SQL Browser service on the remote machine, it can continue to connect by instance name even if the SQL Browser is no longer running on the remote machine, provided that the port number has not changed. Apps that don't use this MRU list (like our pyodbc app) need to have the SQL Browser service running on the remote machine every time they want to connect by instance name.
The most common scenario:
I want to connect to YOUR-PC\SQLEXPRESS. I try doing that from SSMS on MY-PC, but it doesn't work because the SQL Browser was installed with "Start Mode" set to "Manual" on YOUR-PC.
I ask you to start the SQL Browser service on YOUR-PC, and you kindly comply, but you just start the service and forget to change the "Start Mode" setting to "Automatic".
I am able to connect via SSMS (which caches the YOUR-PC\SQLEXPRESS port in the MRU). My python app can connect, too.
After the next time YOUR-PC restarts, I can connect via SSMS (via the MRU) but my python app cannot (because the SQL Browser service is no longer running on YOUR-PC).
Try changing the Driver from 'SQL Server' to 'SQL Server Native Client 11.0'.
I had the same error message and this fixed it for me.
I have this problem.I can connect with Management Studio (SSMS) but not work with pyodbc.
I add version odbc of sql and worked.
change your code to:
conn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER='+server + ';DATABASE=' + db +';UID=' + user + ';PWD=' + password)
If not work change version 17 to 13 if not to 11 .
List versions of ODBC.

Categories