Connector/Python Connection Attributes
MySQL Server has since version 5.6 supported connection attributes for the clients. This has allowed a client to provide information such as which program or connector the client is, the client version, the license, etc. The database administrator can use this information for example to verify whether all clients have been upgraded, which client is executing a particular query, and so forth.
In MySQL 8.0.16 this feature has been included for the X DevAPI in the MySQL connectors as well, including MySQL Connector/Python which I will cover in this blog. First though, let's take a look at how the attributes are exposed in MySQL Server.

Connection Attributes in MySQL Server
The connection attributes are made available in MySQL Server through two tables within the Performance Schema: session_account_connect_attrs
and session_connect_attrs
. The two tables have the same definition – the only difference is for which connections they show the connection attributes.
The session_account_connect_attrs
table includes the attributes for connections using the same user account as for the one querying the table. This is useful if you want to grant permission for a user to check the attributes for their own connections but not for other connections.
On the other hand, session_connect_attrs
shows the attributes for all connections. This is useful for the administrator to check the attributes for all users.
The tables have four columns:
PROCESSLIST_ID
: This is the same ID as inSHOW PROCESSLIST
or thePROCESSLIST_ID
column inperformance_schema.threads
.ATTR_NAME
: This is the name of the attribute, for example_client_name
.ATTR_VALUE
: This is the value for the attribute, for examplemysql-connector-python
.ORDINAL_POSITION
: The attributes have an order. The ordinal position specifies the position of the attribute. The first attribute for the connection has ordinal position 0, the next 1, and so forth.
The PROCESSLIST_ID
and ATTR_NAME
together form the primary key of the tables.
Now that you know how to query the table, let's take a look at how it works with MySQL Connector/Python.
Connector/Python Attributes
There are essentially three different ways to use the connection attributes from MySQL Connector/Python. You can have them disabled. This is the default and means that no attributes will be provided. You can enable them and use the default attributes. And finally, there is support for providing custom attributes. Let's look at each of the two cases where attributes are enabled.

Book
If you want to learn more about using MySQL Connector/Python, then I have written MySQL Connector/Python Revealed published by Apress. The book both covers the traditional Python Database API (PEP 249) and the X DevAPI which is new as of MySQL 8.
The book is available from Apress (print and DRM free ePub+PDF), Amazon (print and Kindle), Barnes & Noble (print), and others.
Enabled with Default Attributes
If you want your Python program to connect to MySQL using the default attributes, all you need to do is to set the connection-attributes
option to True
. You can do that in one of two ways depending on how you set the connection arguments
If you use a dictionary of arguments, you add connection-attributes
as a key with the value set to True
:
import mysqlx
connect_args = {
"host": "127.0.0.1",
"port": 33060,
"user": "pyuser",
"password": "Py@pp4Demo",
"connection-attributes": True,
};
db = mysqlx.get_session(**connect_args)
p_s = db.get_schema("performance_schema")
attr = p_s.get_table("session_account_connect_attrs")
stmt = attr.select()
stmt.where("PROCESSLIST_ID = CONNECTION_ID()")
stmt.order_by("ORDINAL_POSITION")
result = stmt.execute()
print("+------+-----------------+------------------------+---------+")
print("| P_ID | ATTR_NAME | ATTR_VALUE | ORDINAL |")
print("+------+-----------------+------------------------+---------+")
fmt = "| {0:4d} | {1:<15s} | {2:<22s} | {3:7d} |"
for row in result.fetch_all():
print(fmt.format(row[0], row[1], row[2], row[3]))
print("+------+-----------------+------------------------+---------+")
db.close()
The program creates the connection, then queries the performance_schema.session_account_connect_attrs
table using the crud methods. Finally, the result is printed (note that the PROCESSLIST_ID
and ORDINAL_POSITION
columns have had their names shortened in the output to make the output less wide – the process list ID will differ in your output):
+------+-----------------+------------------------+---------+
| P_ID | ATTR_NAME | ATTR_VALUE | ORDINAL |
+------+-----------------+------------------------+---------+
| 45 | _pid | 19944 | 0 |
| 45 | _platform | x86_64 | 1 |
| 45 | _os | Windows-10.0.17134 | 2 |
| 45 | _source_host | MY-LAPTOP | 3 |
| 45 | _client_name | mysql-connector-python | 4 |
| 45 | _client_version | 8.0.16 | 5 |
| 45 | _client_license | GPL-2.0 | 6 |
+------+-----------------+------------------------+---------+
Notice that all of the attribute names start with an underscore. That means it is a built-in attribute. Attribute names starting with an underscore are reserved and can only be set by MySQL itself.
You can also connect using a URI, in that case the connection is made like the following example:
import mysqlx
import urllib
uri = "mysqlx://{0}:{1}@{2}:{3}/?connection-attributes=True".format(
"pyuser",
urllib.parse.quote('Py@pp4Demo', safe=''),
"127.0.0.1",
"33060"
)
db = mysqlx.get_session(uri)
The username, password, host, and port are added through the format()
function to make the code less wide. The important thing here is the connection-attributes=True
. You can also leave out =True
as mentioning the connection-attributes
option without any value is the same as enabling it.
What do you do, if you want to add your own customer attributes? That is supported as well.
Custom Attributes
This far the connection-attributes
option has just been set to True
. However, it also supports taking a list or dictionary as the argument. That can be used to set your own custom attributes.
The easiest way to understand this is to see an example:
import mysqlx
attributes = {
"application": "my_test_app",
"foo": "bar",
"foobar": "",
}
connect_args = {
"host": "127.0.0.1",
"port": 33060,
"user": "pyuser",
"password": "Py@pp4Demo",
"connection-attributes": attributes,
};
db = mysqlx.get_session(**connect_args)
p_s = db.get_schema("performance_schema")
attr = p_s.get_table("session_account_connect_attrs")
stmt = attr.select()
stmt.where("PROCESSLIST_ID = CONNECTION_ID()")
stmt.order_by("ORDINAL_POSITION")
result = stmt.execute()
print("+------+-----------------+------------------------+---------+")
print("| P_ID | ATTR_NAME | ATTR_VALUE | ORDINAL |")
print("+------+-----------------+------------------------+---------+")
fmt = "| {0:4d} | {1:<15s} | {2:<22s} | {3:7d} |"
for row in result.fetch_all():
value = row[2] if row[2] is not None else ""
print(fmt.format(row[0], row[1], value, row[3]))
print("+------+-----------------+------------------------+---------+")
db.close()
Notice in line 29 that it is checked whether the attribute value is None
(NULL
in SQL). When the attribute value is an empty string or no value like for the foobar
attribute, it is returned as None
in the result set.
Alternatively, you can specify the same three connection attributes using a list:
attributes = [
"application=my_test_app",
"foo=bar",
"foobar",
]
connect_args = {
"host": "127.0.0.1",
"port": 33060,
"user": "pyuser",
"password": "Py@pp4Demo",
"connection-attributes": attributes,
};
You can also use an URI of course. You need to use the list syntax for that:
uri = "mysqlx://{0}:{1}@{2}:{3}/" \
+ "?connection-attributes=[application=my_test_app,foo=bar,foobar]".format(
"pyuser",
urllib.parse.quote('Py@pp4Demo', safe=''),
"127.0.0.1",
"33060",
)
These all give the same result (the process list ID will differ):
+------+-----------------+------------------------+---------+
| P_ID | ATTR_NAME | ATTR_VALUE | ORDINAL |
+------+-----------------+------------------------+---------+
| 74 | _pid | 20704 | 0 |
| 74 | _platform | x86_64 | 1 |
| 74 | _os | Windows-10.0.17134 | 2 |
| 74 | _source_host | MY-LAPTOP | 3 |
| 74 | _client_name | mysql-connector-python | 4 |
| 74 | _client_version | 8.0.16 | 5 |
| 74 | _client_license | GPL-2.0 | 6 |
| 74 | application | my_test_app | 7 |
| 74 | foo | bar | 8 |
| 74 | foobar | | 9 |
+------+-----------------+------------------------+---------+
Notice that the built-in attributes are still included and the custom attributes have been added at the end.
That concludes this introduction to connection attributes with the MySQL Connector/Python X DevAPI. I will recommend to enable them by default even if just for the built-in attributes. The attributes can be very handy when debugging issues on the server.
Leave a Reply