I'm trying to connect to a MSSQL database; the issue is that on the network where this script is ran, we use a self-signed certificate internally and I think pyodbc is not happy with that.
The database I am connecting to (MSSQL) lives outside our network - and when I try to connect to the database by running my script on a server (Windows 2016), I get the following errors:
pyodbc.OperationalError: ('08001', '[08001] [Microsoft][ODBC Driver 17 for SQL Server]SSL Provider: The certificate chain was issued by an authority that is not trusted.
I'm not sure how to get pyodbc to recognize that our self-signed cert is 'to be trusted'.
The connection string looks like this:
def get_db_cursor():
driver = os.environ.get("ODBC_DRIVER") # ODBC Driver 17 for SQL Server
host = os.environ.get("db_HOST")
db_name = os.environ.get("db_NAME")
db_user = os.environ.get("db_USER")
db_pass = os.environ.get("db_PASSWORD")
db_port = os.environ.get("db_PORT")
connection = pyodbc.connect(
"DRIVER="
+ driver
+ ";SERVER="
+ host
+ ";PORT="
+ db_port
+ ";DATABASE="
+ db_name
+ ";UID="
+ db_user
+ ";PWD="
+ db_pass
+ ";Encrypt=yes;"
)
db_cursor = connection.cursor()
return db_cursor
I use Encrypt=yes because it's leaving our network and I'd like it encrypted.
I can use TrustServerCertificate=True, but that is not the correct/safe way to do it (but it would work).
I am curious if anyone knows of or has any other ideas on how to get pyodbc to accept a self-signed cert?
Maybe I'm going about this all wrong - but I just can't seem to get this to not throw that error. All help is appreciated.
Related
Has anyone seen this error before?:
ProgrammingError: ('42000', '[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Cannot open database "TC" requested by the login. The login failed. (4060) (SQLDriverConnect); [42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Cannot open database "TC" requested by the login. The login failed. (4060)')
I have verified my credentials and they are 100% correct. As well as, I am using:
python 3.9.7
pyodbc 4.0.0
and when I use:
[x for x in pyodbc.drivers() if x.startswith("ODBC Driver")]
I get:
['ODBC Driver 11 for SQL Server', 'ODBC Driver 17 for SQL Server']
and I'm using SSMS 2014 so ODBC Driver 11 should support that. I am lost as to why this error keeps popping up for my connection string, my connection string is:
cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=' + server + ';DATABASE=' + database + ';UID=' + username + ';PWD=' + password)
So I've verified everything I can think of to this point and it all seems correct, what could the issue be?
Try changing the driver to explicitly use v11
pyodbc.connect(driver='{SQL Server Native Client 11.0}',
server='Server', database='TC', uid='id',pwd='pass')
I am trying to access tables in SQL database in Azure Managed Instance (with IP: xxxx.database.windows.net) from a python script in Azure VM machine but I am getting the Operational Error below. I have tried with 2 different ways below.
Error:
OperationalError: ('08001', '[08001] [Microsoft][SQL Server Native Client 11.0]TCP Provider: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.\r\n (10060) (SQLDriverConnect); [08001] [Microsoft][SQL Server Native Client 11.0]Login timeout expired (0); [08001] [Microsoft][SQL Server Native Client 11.0]A network-related or instance-specific error has occurred while establishing a connection to SQL Server. Server is not found or not accessible. Check if instance name is correct and if SQL Server is configured to allow remote connections. For more information see SQL Server Books Online. (10060)')
1st way with connectionString:
import pandas as pd
from sqlalchemy import create_engine
engine = create_engine("mssql+pyodbc://<username>:<password>#<server>/<database>?driver=SQL+Server+Native+Client+11.0")
query = "select * from table"
df=pd.read_sql(query,engine)
2nd way with connectionString:
import pyodbc
server = 'xxx.database.windows.net'
database = 'database'
username = 'username'
password = 'password'
driver= '{SQL Server Native Client 11.0}'
with pyodbc.connect('DRIVER='+driver+';SERVER='+server+';PORT=1433;DATABASE='+database+';UID='+username+';PWD='+ password) as conn:
with conn.cursor() as cursor:
cursor.execute("SELECT TOP 3 name, collation_name FROM sys.databases")
row = cursor.fetchone()
while row:
print (str(row[0]) + " " + str(row[1]))
row = cursor.fetchone()
Besides, I have also tried to change the driver to drivers below, still no luck.
{ODBC Driver 11 for SQL Server}
{ODBC Driver 13 for SQL Server}
{ODBC Driver 17 for SQL Server}
{SQL Server Native Client 11.0}
Interesting part is, if I try the connect with the same connection string from on-premise machine which is not Azure VM (ex: my local machine or other servers I can RDP to), I can access the database. But when I try on a Azure VM machine, it is timing out. Do you have any ideas how to fix this problem?
Thank you for inputs.
So in the end we foud out that firewall caused this problem. We need to check firewall rules first.
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'
I only have readonly access to a SQL Server db. How do I pass connection parameter "ApplicationIntent=ReadOnly" when using pymssql to connect to the database? If pymssql doesn't support it, is there any other python library that I can use?
The only way to configure readonly connection intent with pymssql seems to be to configure freetds on which it's based, but it did not work out for me. I've had to use pyodbc instead of pymssql
from pyodbc import connect
conn = connect(
'DRIVER={ODBC Driver 17 for SQL Server};SERVER=' + host + ';PORT=' + port + ';DATABASE='
+ database + ';UID=' + user + ';PWD=' + password + ';ApplicationIntent=ReadOnly')
Because pymssql is dependent on FreeTDS
You really need to address the connection parameters to your MS-SQL server used by FreeTDS
Because ApplicationIntent is listed in the freetds user guide as an option you should be able to use it.
pyodbc has a readonly parameter. For example:
import pyodbc
conn = pyodbc.connect(driver='{SQL Server}', host=Server, database=Database,
trusted_connection='yes', user='', password='', readonly = True)
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.