25

I've recently changed my project to use SQLAlchemy and my project runs fine, it used an external MySQL server.

Now I'm trying to work with a different MySQL server with SSL CA, and it doesn't connect.

(It did connect using MySQL Workbench, so the certificate should be fine)

I'm using the following code:

ssl_args = {'ssl': {'ca': ca_path}}
engine = create_engine("mysql+pymysql://<user>:<pass>@<addr>/<schema>",
                        connect_args=ssl_args)

and I get the following error:

Can't connect to MySQL server on '\addr\' ([WinError 10054] An existing connection was forcibly closed by the remote host)

Any suggestions?

4 Answers 4

23

I changed the DBAPI to MySQL-Connector, and used the following code:

ssl_args = {'ssl_ca': ca_path}
engine = create_engine("mysql+mysqlconnector://<user>:<pass>@<addr>/<schema>",
                        connect_args=ssl_args)

And now it works.

Sign up to request clarification or add additional context in comments.

5 Comments

ssl_args should be in this format: ssl_args = {'sslrootcert':'server-ca.pem', 'sslcert':'client-cert.pem', 'sslkey':'client-key.pem'}
Can I specify tls_version in ssl_args?
where do I get this pem file for the client?
ssl_ca did not work for me, but this did: stackoverflow.com/a/14992181
Same as Grimlock, formatting is wrong on this answer, see official documentation: docs.sqlalchemy.org/en/14/dialects/mysql.html#ssl-connections
6

If you just connect from a client machine with an ssl connection (so you don't have access to the cert and key), you could simple add ssl=true to your uri.

Edit:

For example: mysql_db = "mysql+mysqlconnector://<user>:<pass>@<addr>/<schema>?ssl=true"

2 Comments

For Postgres, try sslmode=require if you receive sqlalchemy.exc.ProgrammingError: (psycopg.ProgrammingError) invalid connection option "ssl"
For MySQL with libmysqlclient, use ssl_mode=REQUIRED
4

The official doc is well documented:

engine = create_engine(
    db_url,
    connect_args={
        "ssl": {
            "ssl_ca": "ca.pem",
            "ssl_cert": "client-cert.pem",
            "ssl_key": "client-key.pem"
        }
    }
)

1 Comment

sqlalchemy v.1.4.45 (late 2022) apparently has a bug in docs: keys in subdictionary should not have "ssl_" prefix. See stackoverflow.com/a/14992181/65736 which is still True.
1

Another solution is to use sqlalchemy.engine.url.URL to define the URL and pass it to create_engine.

sqlUrl = sqlalchemy.engine.url.URL(
    drivername="mysql+pymysql",
    username=db_user,
    password=db_pass,
    host=db_host,
    port=3306,
    database=db_name,
    query={"ssl_ca": "main_app/certs/BaltimoreCyberTrustRoot.crt.pem"},
)
create_engine(sqlUrl)

You can include SSL parameters as a dictionary in the query argument.

This approach is useful if you are using Flask to initialize the SqlAlchemy engine with a config parameter like SQLALCHEMY_DATABASE_URI rather than directly using create_engine.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.