Skip to content

bulkcopy() opens a separate PyCoreConnection and appears to ignore Encrypt=no, causing TLS certificate failure #501

@med2604

Description

@med2604

Describe the bug

cursor.bulkcopy() does not behave consistently with a normal mssql_python.connect() session. The regular connection and a normal SELECT work, but bulkcopy() fails because it opens a separate internal connection and handles TLS differently.

What I observed:

  1. mssql_python.connect(...) succeeded
    1. SELECT @@SERVERNAME, DB_NAME(), SUSER_SNAME() on that same connection succeeded
    1. cursor.bulkcopy(...) failed with: TLS handshake failed ... root certificate is not trusted
    1. bulkcopy() only worked after forcing: Encrypt=yes;TrustServerCertificate=yes
      Connection string used:
SERVER=<server>,1433;DATABASE=<database>;UID=...;PWD=...;Encrypt=no;TrustServerCertificate=no

Root cause (from inspecting the installed package):

In cursor.py, bulkcopy() reparses self.connection.connection_str and creates a fresh mssql_py_core.PyCoreConnection(...) for the bulk copy operation instead of reusing the already-open, working connection. Despite Encrypt=no being set in the connection string, the bulkcopy path still attempts a TLS handshake and fails certificate validation.

To reproduce

import mssql_python

conn = mssql_python.connect("SERVER=<server>,1433;DATABASE=<db>;UID=<user>;PWD=<pass>;Encrypt=no;TrustServerCertificate=no")
cursor = conn.cursor()

# This works fine
cursor.execute("SELECT @@SERVERNAME, DB_NAME(), SUSER_SNAME()")
print(cursor.fetchone())

# This fails with TLS handshake error
cursor.bulkcopy("INSERT BULK target_table ([col1] INT, [col2] NVARCHAR(100))", [{"col1": 1, "col2": "test"}])

Expected behavior

bulkcopy() should either:

  1. Reuse the existing working connection, or
    1. Honor the same connection-string encryption settings (Encrypt=no) consistently when creating its internal connection

Further technical details

Python version: 3.12
SQL Server version: SQL Server 2019
Operating system: Windows

  • mssql-python version: 1.4.0
    • Driver: msodbcsql18.dll 18.05.0001
      Additional context

Workaround: Setting Encrypt=yes;TrustServerCertificate=yes forces bulkcopy() to complete the TLS handshake without cert validation. This works but is not equivalent to Encrypt=no and shouldn't be necessary when the main connection path already works without encryption.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions