[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#861580: marked as done ((pre-approval) unblock: mysql-connector-python/2.1.6)



Your message dated Sun, 28 May 2017 12:02:10 +0200
with message-id <20170528100208.GA8672@ugent.be>
and subject line Re: Bug#861580: (pre-approval) unblock: mysql-connector-python/2.1.6
has caused the Debian Bug report #861580,
regarding (pre-approval) unblock: mysql-connector-python/2.1.6
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
861580: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=861580
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Hello,
BTS 861511 was reported yesterday against mysql-connector-python stating the new
upstream version (2.1.6) fixes CVE-2017-3590.

The upstream versions diff (attached) is quite important, so i would understand
if you decide not to accept a potential upload of this new version aiming for an
unblock to strech, but i would still like you to have a look and decide on it.

Thanks,
Sandro

-- System Information:
Debian Release: stretch/sid
  APT prefers unstable
  APT policy: (500, 'unstable'), (1, 'experimental')
Architecture: amd64
 (x86_64)
Foreign Architectures: i386

Kernel: Linux 4.2.0-1-amd64 (SMP w/8 CPU cores)
Locale: LANG=en_US.utf8, LC_CTYPE=en_US.utf8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
diff --git a/CHANGES.txt b/CHANGES.txt
index 18112d1..6e2c797 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -3,11 +3,23 @@ MySQL Connector/Python 2.1 - Release Notes & Changes
 ====================================================
 
 MySQL Connector/Python
-Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
 
 Full release notes:
  http://dev.mysql.com/doc/relnotes/connector-python/en/
 
+v2.1.6
+======
+
+- BUG#25726671: Fix compatibility issues with the latest Django versions
+- BUG#25558885: Set default connection timeout to pure connector/python
+- BUG#25397650: Verify server certificate only if ssl_verify_cert is True
+- BUG#25589496: Don't convert to unicode if non-ascii data is present
+- BUG#25383644: Add connection back to pool on exception
+- BUG#22476689: Importing world.sql fails with cext enabled
+- BUG#20736339: Expect multiple include directories from mysql_config
+- BUG#19685386: C extension tests are failing using MySQL 5.7.4
+
 v2.1.5
 ======
 
diff --git a/PKG-INFO b/PKG-INFO
index 4af4d6f..9ab448d 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: mysql-connector-python
-Version: 2.1.5
+Version: 2.1.6
 Summary: MySQL driver written in Python
 Home-page: http://dev.mysql.com/doc/connector-python/en/index.html
 Author: Oracle and/or its affiliates
@@ -27,6 +27,8 @@ Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3.1
 Classifier: Programming Language :: Python :: 3.2
 Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
 Classifier: Topic :: Database
 Classifier: Topic :: Software Development
 Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
diff --git a/README.txt b/README.txt
index 773af0b..46cce18 100644
--- a/README.txt
+++ b/README.txt
@@ -3,7 +3,7 @@ MySQL Connector/Python 2.1
 ==========================
 
 MySQL Connector/Python
-Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
 
 License information can be found in the LICENSE.txt file.
 
@@ -28,7 +28,7 @@ doubt, this particular copy of the software is released
 under the version 2 of the GNU General Public License.
 MySQL Connector/Python is brought to you by Oracle.
 
-Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
 
 License information can be found in the LICENSE.txt file.
 
diff --git a/lib/cpy_distutils.py b/lib/cpy_distutils.py
index e944ce6..04741ea 100644
--- a/lib/cpy_distutils.py
+++ b/lib/cpy_distutils.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -136,21 +136,7 @@ def unix_lib_is64bit(lib_file):
     return False
 
 
-def get_mysql_config_info(mysql_config):
-    """Get MySQL information using mysql_config tool
-
-    Returns a dict.
-    """
-    options = ['cflags', 'include', 'libs', 'libs_r', 'plugindir', 'version']
-
-    cmd = [mysql_config] + [ "--{0}".format(opt) for opt in options ]
-
-    try:
-        proc = Popen(cmd, stdout=PIPE, universal_newlines=True)
-        stdout, _ = proc.communicate()
-    except OSError as exc:
-        raise DistutilsExecError("Failed executing mysql_config: {0}".format(
-            str(exc)))
+def parse_mysql_config_info(options, stdout):
     log.debug("# stdout: {0}".format(stdout))
     info = {}
     for option, line in zip(options, stdout.split('\n')):
@@ -173,7 +159,28 @@ def get_mysql_config_info(mysql_config):
     info['lib_r_dir'] = libs[0].replace('-L', '')
     info['libs_r'] = [ lib.replace('-l', '') for lib in libs[1:] ]
 
-    info['include'] = info['include'].replace('-I', '')
+    info['include'] = [x.strip() for x in info['include'].split('-I')[1:]]
+
+    return info
+
+
+def get_mysql_config_info(mysql_config):
+    """Get MySQL information using mysql_config tool
+
+    Returns a dict.
+    """
+    options = ['cflags', 'include', 'libs', 'libs_r', 'plugindir', 'version']
+
+    cmd = [mysql_config] + [ "--{0}".format(opt) for opt in options ]
+
+    try:
+        proc = Popen(cmd, stdout=PIPE, universal_newlines=True)
+        stdout, _ = proc.communicate()
+    except OSError as exc:
+        raise DistutilsExecError("Failed executing mysql_config: {0}".format(
+            str(exc)))
+
+    info = parse_mysql_config_info(options, stdout)
 
     # Try to figure out the architecture
     info['arch'] = None
@@ -316,7 +323,7 @@ class BuildExtDynamic(build_ext):
                 else:
                     raise OSError("Unsupported platform: %s" % os.name)
 
-                include_dir = os.path.join(connc_loc, 'include')
+                include_dirs = [os.path.join(connc_loc, 'include')]
                 if os.name == 'nt':
                     libraries = ['libmysql']
                 else:
@@ -341,19 +348,20 @@ class BuildExtDynamic(build_ext):
                 log.error(err_version)
                 sys.exit(1)
 
-            include_dir = myc_info['include']
+            include_dirs = myc_info['include']
             libraries = myc_info['libs']
             library_dirs = myc_info['lib_dir']
             self._mysql_config_info = myc_info
             self.arch = self._mysql_config_info['arch']
             connc_64bit = self.arch == 'x86_64'
 
-        if not os.path.exists(include_dir):
-            log.error(err_invalid_loc, connc_loc)
-            sys.exit(1)
+        for include_dir in include_dirs:
+            if not os.path.exists(include_dir):
+                log.error(err_invalid_loc, connc_loc)
+                sys.exit(1)
 
         # Set up the build_ext class
-        self.include_dirs.append(include_dir)
+        self.include_dirs.extend(include_dirs)
         self.libraries.extend(libraries)
         self.library_dirs.append(library_dirs)
 
diff --git a/lib/mysql/connector/abstracts.py b/lib/mysql/connector/abstracts.py
index c83a527..928bd8c 100644
--- a/lib/mysql/connector/abstracts.py
+++ b/lib/mysql/connector/abstracts.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -62,7 +62,7 @@ class MySQLConnectionAbstract(object):
         self._use_unicode = True
         self._get_warnings = False
         self._raise_on_warnings = False
-        self._connection_timeout = None
+        self._connection_timeout = DEFAULT_CONFIGURATION["connect_timeout"]
         self._buffered = False
         self._unread_result = False
         self._have_next_result = False
@@ -231,6 +231,13 @@ class MySQLConnectionAbstract(object):
         except KeyError:
             self._consume_results = False
 
+        # Configure auth_plugin
+        try:
+            self._auth_plugin = config['auth_plugin']
+            del config['auth_plugin']
+        except KeyError:
+            self._auth_plugin = ''
+
         # Configure character set and collation
         if 'charset' in config or 'collation' in config:
             try:
diff --git a/lib/mysql/connector/connection.py b/lib/mysql/connector/connection.py
index 453c73e..ebf0c38 100644
--- a/lib/mysql/connector/connection.py
+++ b/lib/mysql/connector/connection.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -78,7 +78,6 @@ class MySQLConnection(MySQLConnectionAbstract):
         self._use_unicode = True
         self._get_warnings = False
         self._raise_on_warnings = False
-        self._connection_timeout = None
         self._buffered = False
         self._unread_result = False
         self._have_next_result = False
@@ -184,6 +183,7 @@ class MySQLConnection(MySQLConnectionAbstract):
 
         Returns subclass of MySQLBaseSocket.
         """
+        # pylint: disable=R0204
         conn = None
         if self.unix_socket and os.name != 'nt':
             conn = MySQLUnixSocket(unix_socket=self.unix_socket)
@@ -191,6 +191,7 @@ class MySQLConnection(MySQLConnectionAbstract):
             conn = MySQLTCPSocket(host=self.server_host,
                                   port=self.server_port,
                                   force_ipv6=self._force_ipv6)
+        # pylint: enable=R0204
         conn.set_connection_timeout(self._connection_timeout)
         return conn
 
@@ -440,14 +441,17 @@ class MySQLConnection(MySQLConnectionAbstract):
                 rows = self._protocol.read_binary_result(
                     self._socket, columns, count)
             else:
-                rows = self._protocol.read_text_result(self._socket, self._server_version, count=count)
+                rows = self._protocol.read_text_result(self._socket,
+                                                       self._server_version,
+                                                       count=count)
         except errors.Error as err:
             self.unread_result = False
             raise err
 
         if rows[-1] is not None:
-            ek = rows[-1] # OK or EOF
-            self._handle_server_status(ek['status_flag'] if 'status_flag' in ek else ek['server_status'])
+            row = rows[-1]  # OK or EOF
+            self._handle_server_status(row['status_flag'] if 'status_flag' in
+                                       row else row['server_status'])
             self.unread_result = False
 
         return rows
diff --git a/lib/mysql/connector/connection_cext.py b/lib/mysql/connector/connection_cext.py
index 9c00a9a..cf29c3b 100644
--- a/lib/mysql/connector/connection_cext.py
+++ b/lib/mysql/connector/connection_cext.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -54,6 +54,7 @@ else:
     HAVE_CMYSQL = True
 # pylint: enable=F0401,C0413
 
+
 class CMySQLConnection(MySQLConnectionAbstract):
 
     """Class initiating a MySQL Connection using Connector/C"""
@@ -64,7 +65,6 @@ class CMySQLConnection(MySQLConnectionAbstract):
             raise RuntimeError(
                 "MySQL Connector/Python C Extension not available")
         self._cmysql = None
-        self._connection_timeout = 2
         self._columns = []
         self.converter = None
         super(CMySQLConnection, self).__init__(**kwargs)
@@ -139,12 +139,11 @@ class CMySQLConnection(MySQLConnectionAbstract):
 
     def _open_connection(self):
         charset_name = CharacterSet.get_info(self._charset_id)[0]
-
-        self._cmysql = _mysql_connector.MySQL(
+        self._cmysql = _mysql_connector.MySQL(  # pylint: disable=E1101
             buffered=self._buffered,
             raw=self._raw,
             charset_name=charset_name,
-            connection_timeout=int(self._connection_timeout or 10),
+            connection_timeout=(self._connection_timeout or 0),
             use_unicode=self._use_unicode,
             auth_plugin=self._auth_plugin)
 
@@ -260,6 +259,7 @@ class CMySQLConnection(MySQLConnectionAbstract):
             raise AttributeError("count should be 1 or higher, or None")
 
         counter = 0
+        # pylint: disable=R0204
         try:
             row = self._cmysql.fetch_row()
             while row:
@@ -278,7 +278,7 @@ class CMySQLConnection(MySQLConnectionAbstract):
             self.free_result()
             raise errors.get_mysql_exception(msg=exc.msg, errno=exc.errno,
                                              sqlstate=exc.sqlstate)
-
+        # pylint: enable=R0204
         return rows
 
     def get_row(self, binary=False, columns=None):
diff --git a/lib/mysql/connector/constants.py b/lib/mysql/connector/constants.py
index 8d27cb0..709e675 100644
--- a/lib/mysql/connector/constants.py
+++ b/lib/mysql/connector/constants.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -686,7 +686,7 @@ class CharacterSet(_Constants):
         return tuple(res)
 
 
-class SQLMode(_Constants):  # pylint: disable=R0921
+class SQLMode(_Constants):
     """MySQL SQL Modes
 
     The numeric values of SQL Modes are not interesting, only the names
diff --git a/lib/mysql/connector/cursor.py b/lib/mysql/connector/cursor.py
index 09b7b54..3002192 100644
--- a/lib/mysql/connector/cursor.py
+++ b/lib/mysql/connector/cursor.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -41,7 +41,7 @@ RE_SQL_ON_DUPLICATE = re.compile(
     re.I | re.M | re.S)
 RE_SQL_INSERT_STMT = re.compile(
     r"({0}|\s)*INSERT({0}|\s)*INTO\s+[`'\"]?.+[`'\"]?(?:\.[`'\"]?.+[`'\"]?)"
-     "{{0,2}}\s+VALUES\s*\(.+(?:\s*,.+)*\)".format(SQL_COMMENT),
+    r"{{0,2}}\s+VALUES\s*\(.+(?:\s*,.+)*\)".format(SQL_COMMENT),
     re.I | re.M | re.S)
 RE_SQL_INSERT_VALUES = re.compile(r'.*VALUES\s*(\(.*\)).*', re.I | re.M | re.S)
 RE_PY_PARAM = re.compile(b'(%s)')
@@ -97,20 +97,27 @@ def _bytestr_format_dict(bytestr, value_dict):
     b'x=%(y)s y=%(x)s'
     """
     def replace(matchobj):
+        """Replace pattern."""
         value = None
         groups = matchobj.groupdict()
         if groups["conversion_type"] == b"%":
             value = b"%"
         if groups["conversion_type"] == b"s":
-            key = groups["mapping_key"].encode("utf-8") \
-                  if PY2 else groups["mapping_key"]
+            key = groups["mapping_key"]
             value = value_dict[key]
         if value is None:
             raise ValueError("Unsupported conversion_type: {0}"
                              "".format(groups["conversion_type"]))
-        return value.decode("utf-8") if PY2 else value
-    return RE_PY_MAPPING_PARAM.sub(replace, bytestr.decode("utf-8")
-                                   if PY2 else bytestr)
+        return bytes(value) if PY2 else value
+
+    stmt = RE_PY_MAPPING_PARAM.sub(replace, bytestr)
+    if PY2:
+        try:
+            return stmt.decode("utf-8")
+        except UnicodeDecodeError:
+            pass
+    return stmt
+
 
 class CursorBase(MySQLCursorAbstract):
     """
@@ -749,10 +756,12 @@ class MySQLCursor(CursorBase):
             can_consume_results = self._connection._consume_results
             for result in self._connection.cmd_query_iter(call):
                 self._connection._consume_results = False
+                # pylint: disable=R0204
                 if self._raw:
                     tmp = MySQLCursorBufferedRaw(self._connection._get_self())
                 else:
                     tmp = MySQLCursorBuffered(self._connection._get_self())
+                # pylint: enable=R0204
                 tmp._executed = "(a result of {0})".format(call)
                 tmp._handle_result(result)
                 if tmp._warnings is not None:
@@ -760,7 +769,7 @@ class MySQLCursor(CursorBase):
                 if 'columns' in result:
                     results.append(tmp)
             self._connection._consume_results = can_consume_results
-            #pylint: enable=W0212
+            # pylint: enable=W0212
 
             if argnames:
                 select = "SELECT {0}".format(','.join(argtypes))
diff --git a/lib/mysql/connector/cursor_cext.py b/lib/mysql/connector/cursor_cext.py
index 4dd6e9a..df5fed3 100644
--- a/lib/mysql/connector/cursor_cext.py
+++ b/lib/mysql/connector/cursor_cext.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -28,6 +28,8 @@ from collections import namedtuple
 import re
 import weakref
 
+from _mysql_connector import MySQLInterfaceError  # pylint: disable=F0401,E0611
+
 from .abstracts import MySQLConnectionAbstract, MySQLCursorAbstract
 from .catch23 import PY2, isunicode
 from . import errors
@@ -39,7 +41,6 @@ from .cursor import (
     RE_SQL_SPLIT_STMTS
 )
 
-from _mysql_connector import MySQLInterfaceError  # pylint: disable=F0401
 
 class _ParamSubstitutor(object):
 
@@ -204,7 +205,10 @@ class CMySQLCursor(MySQLCursorAbstract):
                 if exc.errno != CR_NO_RESULT_SET:
                     raise
             i += 1
-            self._executed = executed_list[i].strip()
+            try:
+                self._executed = executed_list[i].strip()
+            except IndexError:
+                self._executed = executed_list[0]
             yield self
         return
 
@@ -429,14 +433,14 @@ class CMySQLCursor(MySQLCursorAbstract):
             results = []
             while self._cnx.result_set_available:
                 result = self._cnx.fetch_eof_columns()
-                # pylint: disable=W0212
+                # pylint: disable=W0212,R0204
                 if self._raw:
                     cur = CMySQLCursorBufferedRaw(self._cnx._get_self())
                 else:
                     cur = CMySQLCursorBuffered(self._cnx._get_self())
                 cur._executed = "(a result of {0})".format(call)
                 cur._handle_result(result)
-                # pylint: enable=W0212
+                # pylint: enable=W0212,R0204
                 results.append(cur)
                 self._cnx.next_result()
             self._stored_results = results
@@ -807,4 +811,3 @@ class CMySQLCursorPrepared(CMySQLCursor):
         super(CMySQLCursorPrepared, self).__init__(connection)
         raise NotImplementedError(
             "Alternative: Use connection.MySQLCursorPrepared")
-
diff --git a/lib/mysql/connector/django/introspection.py b/lib/mysql/connector/django/introspection.py
index 77e5503..35b3018 100644
--- a/lib/mysql/connector/django/introspection.py
+++ b/lib/mysql/connector/django/introspection.py
@@ -279,9 +279,8 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
                     'unique': False,
                     'index': False,
                     'check': False,
-                    'foreign_key': (
-                        (ref_table, ref_column) if ref_column else None,
-                    )
+                    'foreign_key': \
+                        (ref_table, ref_column) if ref_column else None
                 }
             constraints[constraint]['columns'].add(column)
         # Now get the constraint types
diff --git a/lib/mysql/connector/django/operations.py b/lib/mysql/connector/django/operations.py
index 127750d..8b23290 100644
--- a/lib/mysql/connector/django/operations.py
+++ b/lib/mysql/connector/django/operations.py
@@ -185,6 +185,10 @@ class DatabaseOperations(BaseDatabaseOperations):
                              'value for AutoField.')
         return value
 
+    if django.VERSION > (1, 8):
+        def adapt_datetimefield_value(self, value):
+            return self.value_to_db_datetime(value)
+
     def value_to_db_datetime(self, value):
         if value is None:
             return None
@@ -202,6 +206,10 @@ class DatabaseOperations(BaseDatabaseOperations):
             return datetime_to_mysql(value)
         return self.connection.converter.to_mysql(value)
 
+    if django.VERSION > (1, 8):
+        def adapt_timefield_value(self, value):
+            return self.value_to_db_time(value)
+
     def value_to_db_time(self, value):
         if value is None:
             return None
@@ -218,9 +226,15 @@ class DatabaseOperations(BaseDatabaseOperations):
     def max_name_length(self):
         return 64
 
-    def bulk_insert_sql(self, fields, num_values):
-        items_sql = "({0})".format(", ".join(["%s"] * len(fields)))
-        return "VALUES " + ", ".join([items_sql] * num_values)
+    if django.VERSION < (1, 9):
+        def bulk_insert_sql(self, fields, num_values):
+            items_sql = "({0})".format(", ".join(["%s"] * len(fields)))
+            return "VALUES " + ", ".join([items_sql] * num_values)
+    else:
+        def bulk_insert_sql(self, fields, placeholder_rows):
+            placeholder_rows_sql = (", ".join(row) for row in placeholder_rows)
+            values_sql = ", ".join("({0})".format(sql) for sql in placeholder_rows_sql)
+            return "VALUES " + values_sql
 
     if django.VERSION < (1, 8):
         def year_lookup_bounds(self, value):
diff --git a/lib/mysql/connector/errors.py b/lib/mysql/connector/errors.py
index ea354f2..d2eedfb 100644
--- a/lib/mysql/connector/errors.py
+++ b/lib/mysql/connector/errors.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -301,4 +301,5 @@ _ERROR_EXCEPTIONS = {
     2049: NotSupportedError,
     2055: OperationalError,
     2061: InterfaceError,
+    2026: InterfaceError,
 }
diff --git a/lib/mysql/connector/fabric/__init__.py b/lib/mysql/connector/fabric/__init__.py
index b3d6a06..c88fe03 100644
--- a/lib/mysql/connector/fabric/__init__.py
+++ b/lib/mysql/connector/fabric/__init__.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -26,6 +26,15 @@
 
 from collections import namedtuple
 
+from .connection import (
+    MODE_READONLY, MODE_READWRITE,
+    STATUS_PRIMARY, STATUS_SECONDARY,
+    SCOPE_GLOBAL, SCOPE_LOCAL,
+    Fabric, FabricConnection,
+    MySQLFabricConnection,
+    FabricSet,
+)
+
 # Order of field_names must match how Fabric is returning the data
 FabricMySQLServer = namedtuple(
     'FabricMySQLServer',
@@ -39,15 +48,6 @@ FabricShard = namedtuple(
      'shard', 'shard_type', 'group', 'global_group']
     )
 
-from .connection import (
-    MODE_READONLY, MODE_READWRITE,
-    STATUS_PRIMARY, STATUS_SECONDARY,
-    SCOPE_GLOBAL, SCOPE_LOCAL,
-    Fabric, FabricConnection,
-    MySQLFabricConnection,
-    FabricSet,
-)
-
 
 def connect(**kwargs):
     """Create a MySQLFabricConnection object"""
diff --git a/lib/mysql/connector/fabric/caching.py b/lib/mysql/connector/fabric/caching.py
index a24d6b1..9073498 100644
--- a/lib/mysql/connector/fabric/caching.py
+++ b/lib/mysql/connector/fabric/caching.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -116,32 +116,33 @@ class CacheShardTable(CacheEntry):
     def add_partition(self, key, group):
         """Add sharding information for a group"""
         if self.shard_type == 'RANGE':
-            key = int(key)
+            _key = int(key)
         elif self.shard_type == 'RANGE_DATETIME':
             try:
                 if ':' in key:
-                    key = datetime.strptime(key, "%Y-%m-%d %H:%M:%S")
+                    # pylint: disable=R0204
+                    _key = datetime.strptime(key, "%Y-%m-%d %H:%M:%S")
                 else:
-                    key = datetime.strptime(key, "%Y-%m-%d").date()
+                    _key = datetime.strptime(key, "%Y-%m-%d").date()
             except:
                 raise ValueError(
                     "RANGE_DATETIME key could not be parsed, was: {0}".format(
                         key
                     ))
         elif self.shard_type == 'RANGE_STRING':
-            pass
+            _key = key
         elif self.shard_type == "HASH":
-            pass
+            _key = key
         else:
             raise ValueError("Unsupported sharding type {0}".format(
                 self.shard_type
             ))
-        self.partitioning[key] = {
+        self.partitioning[_key] = {
             'group': group,
         }
         self.reset_ttl()
-        bisect.insort_right(self.keys, key)
-        insort_right_rev(self.keys_reversed, key)
+        bisect.insort_right(self.keys, _key)
+        insort_right_rev(self.keys_reversed, _key)
 
     @classmethod
     def hash_index(cls, part1, part2=None):
@@ -175,6 +176,7 @@ class CacheGroup(CacheEntry):
             group=self.group_name,
         )
 
+
 class FabricCache(object):
     """Singleton class for caching Fabric data
 
diff --git a/lib/mysql/connector/fabric/connection.py b/lib/mysql/connector/fabric/connection.py
index 44da175..7e2f657 100644
--- a/lib/mysql/connector/fabric/connection.py
+++ b/lib/mysql/connector/fabric/connection.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -27,13 +27,34 @@ import sys
 import datetime
 import time
 import uuid
-from base64 import b16decode
-from bisect import bisect
-from hashlib import md5
 import logging
 import socket
 import collections
 
+from base64 import b16decode
+from bisect import bisect
+from hashlib import md5
+
+import mysql.connector
+
+from ..connection import MySQLConnection
+from ..conversion import MySQLConverter
+from ..pooling import MySQLConnectionPool
+from ..errors import (
+    Error, InterfaceError, NotSupportedError, MySQLFabricError, InternalError,
+    DatabaseError
+)
+from ..cursor import (
+    MySQLCursor, MySQLCursorBuffered,
+    MySQLCursorRaw, MySQLCursorBufferedRaw
+)
+from .. import errorcode
+from . import FabricMySQLServer, FabricShard
+from .caching import FabricCache
+from .balancing import WeightedRoundRobin
+from .. import version
+from ..catch23 import PY2, isunicode, UNICODE_TYPES
+
 # pylint: disable=F0401,E0611
 try:
     from xmlrpclib import Fault, ServerProxy, Transport
@@ -47,7 +68,7 @@ except ImportError:
 
 if sys.version_info[0] == 2:
     try:
-        from httplib import HTTPSConnection
+        from httplib import HTTPSConnection  # pylint: disable=C0412
     except ImportError:
         HAVE_SSL = False
     else:
@@ -59,26 +80,7 @@ else:
         HAVE_SSL = False
     else:
         HAVE_SSL = True
-# pylint: enable=F0401,E0611
 
-import mysql.connector
-from ..connection import MySQLConnection
-from ..conversion import MySQLConverter
-from ..pooling import MySQLConnectionPool
-from ..errors import (
-    Error, InterfaceError, NotSupportedError, MySQLFabricError, InternalError,
-    DatabaseError
-)
-from ..cursor import (
-    MySQLCursor, MySQLCursorBuffered,
-    MySQLCursorRaw, MySQLCursorBufferedRaw
-)
-from .. import errorcode
-from . import FabricMySQLServer, FabricShard
-from .caching import FabricCache
-from .balancing import WeightedRoundRobin
-from .. import version
-from ..catch23 import PY2, isunicode, UNICODE_TYPES
 
 RESET_CACHE_ON_ERROR = (
     errorcode.CR_SERVER_LOST,
@@ -213,8 +215,7 @@ class MySQLRPCProtocol(object):
             kwargs = self._process_params_dict(kwargs)
             params.extend(kwargs)
 
-        params = ', '.join(params)
-        return params
+        return ', '.join(params)
 
     def execute(self, group, command, *args, **kwargs):
         """Executes the given command with MySQL protocol
@@ -460,7 +461,7 @@ if HAVE_SSL:
             if PY2:
                 urllib2.HTTPSHandler.__init__(self)
             else:
-                super().__init__()  # pylint: disable=W0104
+                super().__init__()  # pylint: disable=W0104,E1004
             self._ssl_config = ssl_config
 
         def https_open(self, req):
@@ -488,7 +489,7 @@ class FabricTransport(Transport):
         if PY2:
             Transport.__init__(self, use_datetime=False)
         else:
-            super().__init__(use_datetime=False)
+            super().__init__(use_datetime=False)  # pylint: disable=E1004
         self._username = username
         self._password = password
         self._use_datetime = use_datetime
diff --git a/lib/mysql/connector/locales/__init__.py b/lib/mysql/connector/locales/__init__.py
index ad784e6..cd5e54f 100644
--- a/lib/mysql/connector/locales/__init__.py
+++ b/lib/mysql/connector/locales/__init__.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -68,4 +68,3 @@ def get_client_error(error, language='eng'):
             return None
 
     raise ValueError("error argument needs to be either an integer or string")
-
diff --git a/lib/mysql/connector/network.py b/lib/mysql/connector/network.py
index 1ef55a3..7c097b7 100644
--- a/lib/mysql/connector/network.py
+++ b/lib/mysql/connector/network.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -168,9 +168,9 @@ class BaseMySQLSocket(object):
                 tmpbuf = bytearray()
                 for pkt in pkts:
                     tmpbuf += pkt
-                tmpbuf = buffer(tmpbuf)  # pylint: disable=E0602
+                tmpbuf = buffer(tmpbuf)  # pylint: disable=E0602,R0204
             else:
-                tmpbuf = b''.join(pkts)
+                tmpbuf = b''.join(pkts)  # pylint: disable=R0204
             del pkts
             zbuf = zlib.compress(tmpbuf[:16384])
             header = (struct.pack('<I', len(zbuf))[0:3]
@@ -181,7 +181,7 @@ class BaseMySQLSocket(object):
             zpkts.append(header + zbuf)
             tmpbuf = tmpbuf[16384:]
             pllen = len(tmpbuf)
-            self.next_compressed_packet_number
+            self.next_compressed_packet_number  # pylint: disable=W0104
             while pllen > maxpktlen:
                 zbuf = zlib.compress(tmpbuf[:maxpktlen])
                 header = (struct.pack('<I', len(zbuf))[0:3]
@@ -192,7 +192,7 @@ class BaseMySQLSocket(object):
                 zpkts.append(header + zbuf)
                 tmpbuf = tmpbuf[maxpktlen:]
                 pllen = len(tmpbuf)
-                self.next_compressed_packet_number
+                self.next_compressed_packet_number  # pylint: disable=W0104
             if tmpbuf:
                 zbuf = zlib.compress(tmpbuf)
                 header = (struct.pack('<I', len(zbuf))[0:3]
diff --git a/lib/mysql/connector/pooling.py b/lib/mysql/connector/pooling.py
index 17d2f59..b671120 100644
--- a/lib/mysql/connector/pooling.py
+++ b/lib/mysql/connector/pooling.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -112,12 +112,13 @@ class PooledMySQLConnection(object):
         When the pool is configured to reset the session, the session
         state will be cleared by re-authenticating the user.
         """
-        cnx = self._cnx
-        if self._cnx_pool.reset_session:
-            cnx.reset_session()
-
-        self._cnx_pool.add_connection(cnx)
-        self._cnx = None
+        try:
+            cnx = self._cnx
+            if self._cnx_pool.reset_session:
+                cnx.reset_session()
+        finally:
+            self._cnx_pool.add_connection(cnx)
+            self._cnx = None
 
     def config(self, **kwargs):
         """Configuration is done through the pool"""
diff --git a/lib/mysql/connector/protocol.py b/lib/mysql/connector/protocol.py
index 6c75a0a..9014897 100644
--- a/lib/mysql/connector/protocol.py
+++ b/lib/mysql/connector/protocol.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -29,7 +29,7 @@ import datetime
 from decimal import Decimal
 
 from .constants import (
-    FieldFlag, ServerCmd, FieldType, ClientFlag, MAX_MYSQL_TABLE_COLUMNS)
+    FieldFlag, ServerCmd, FieldType, ClientFlag)
 from . import errors, utils
 from .authentication import get_auth_plugin
 from .catch23 import PY2, struct_unpack
@@ -61,7 +61,7 @@ class MySQLProtocol(object):
                 ssl_enabled=ssl_enabled)
             plugin_auth_response = auth.auth_response()
         except (TypeError, errors.InterfaceError) as exc:
-            raise errors.ProgrammingError(
+            raise errors.InterfaceError(
                 "Failed authentication: {0}".format(str(exc)))
 
         if client_flags & ClientFlag.SECURE_CONNECTION:
@@ -90,7 +90,7 @@ class MySQLProtocol(object):
             username_bytes = username.encode('utf8')  # pylint: disable=E1103
         except AttributeError:
             # Username is already bytes
-            username_bytes = username
+            username_bytes = username  # pylint: disable=R0204
         packet = struct.pack('<IIB{filler}{usrlen}sx'.format(
             filler='x' * 23, usrlen=len(username_bytes)),
                              client_flags, max_allowed_packet, charset,
@@ -141,7 +141,7 @@ class MySQLProtocol(object):
             username_bytes = username.encode('utf8')  # pylint: disable=E1103
         except AttributeError:
             # Username is already bytes
-            username_bytes = username
+            username_bytes = username  # pylint: disable=R0204
         packet = struct.pack('<B{usrlen}sx'.format(usrlen=len(username_bytes)),
                              ServerCmd.CHANGE_USER, username_bytes)
 
@@ -328,7 +328,7 @@ class MySQLProtocol(object):
                     packet = sock.recv()
                 datas.append(packet[4:])
                 rowdata = utils.read_lc_string_list(bytearray(b'').join(datas))
-            elif (packet[4] == 254 and packet[0] < 7):
+            elif packet[4] == 254 and packet[0] < 7:
                 eof = self.parse_eof(packet)
                 rowdata = None
             else:
@@ -385,7 +385,7 @@ class MySQLProtocol(object):
             mcs = 0
             if length == 11:
                 mcs = struct_unpack('I', packet[8:length + 1])[0]
-            value = datetime.datetime(
+            value = datetime.datetime(  # pylint: disable=R0204
                 year=struct_unpack('H', packet[1:3])[0],
                 month=packet[3],
                 day=packet[4],
diff --git a/lib/mysql/connector/version.py b/lib/mysql/connector/version.py
index a3c311c..f6b49d5 100644
--- a/lib/mysql/connector/version.py
+++ b/lib/mysql/connector/version.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -26,7 +26,7 @@ The file version.py gets installed and is available after installation
 as mysql.connector.version.
 """
 
-VERSION = (2, 1, 5, '', 0)
+VERSION = (2, 1, 6, '', 0)
 
 if VERSION[3] and VERSION[4]:
     VERSION_TEXT = '{0}.{1}.{2}{3}{4}'.format(*VERSION)
diff --git a/setupinfo.py b/setupinfo.py
index 6784a38..18998ae 100644
--- a/setupinfo.py
+++ b/setupinfo.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -88,8 +88,8 @@ libraries and implements the DB API v2.0 specification (PEP-249).
 """
 author = 'Oracle and/or its affiliates'
 author_email = ''
-maintainer = 'Geert Vanderkelen'
-maintainer_email = 'geert.vanderkelen@oracle.com'
+maintainer = 'Nuno Mariz'
+maintainer_email = 'nuno.mariz@oracle.com'
 cpy_gpl_license = "GNU GPLv2 (with FOSS License Exception)"
 keywords = "mysql db",
 url = 'http://dev.mysql.com/doc/connector-python/en/index.html'
@@ -109,6 +109,8 @@ classifiers = [
     'Programming Language :: Python :: 3.1',
     'Programming Language :: Python :: 3.2',
     'Programming Language :: Python :: 3.3',
+    'Programming Language :: Python :: 3.4',
+    'Programming Language :: Python :: 3.5',
     'Topic :: Database',
     'Topic :: Software Development',
     'Topic :: Software Development :: Libraries :: Application Frameworks',
diff --git a/src/mysql_capi.c b/src/mysql_capi.c
index e1f995b..370cceb 100644
--- a/src/mysql_capi.c
+++ b/src/mysql_capi.c
@@ -1,6 +1,6 @@
 /*
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -363,7 +363,7 @@ MySQL_init(MySQL *self, PyObject *args, PyObject *kwds)
 
     // Initialization expect -1 when parsing arguments failed
     if (!PyArg_ParseTupleAndKeywords(args, kwds,
-                                     "|O!O!O!O!O!O", kwlist,
+                                     "|O!O!O!O!O!O!", kwlist,
                                      &PyBool_Type, &self->buffered_at_connect,
                                      &PyBool_Type, &self->raw_at_connect,
                                      &PyStringType, &self->charset_name,
@@ -393,6 +393,10 @@ MySQL_init(MySQL *self, PyObject *args, PyObject *kwds)
 
     if (auth_plugin)
     {
+        if (strcmp(PyStringAsString(auth_plugin), "") == 0)
+        {
+            auth_plugin= Py_None;
+        }
         if (auth_plugin != Py_None)
         {
             tmp= self->auth_plugin;
@@ -1036,6 +1040,7 @@ MySQL_connect(MySQL *self, PyObject *args, PyObject *kwds)
 	unsigned int ssl_mode;
 #endif
 	my_bool abool;
+	my_bool ssl_enabled= 0;
 	MYSQL *res;
 
 	static char *kwlist[]=
@@ -1112,8 +1117,8 @@ MySQL_connect(MySQL *self, PyObject *args, PyObject *kwds)
     mysql_options(&self->session, MYSQL_OPT_WRITE_TIMEOUT, (char*)&tmp_uint);
 
     if (ssl_ca || ssl_cert || ssl_key) {
+        ssl_enabled= 1;
 #if MYSQL_VERSION_ID > 50703 && MYSQL_VERSION_ID < 50711
-        printf(">>>> %d\n", MYSQL_VERSION_ID);
         {
             abool= 1;
             mysql_options(&self->session, MYSQL_OPT_SSL_ENFORCE, (char*)&abool);
@@ -1140,8 +1145,10 @@ MySQL_connect(MySQL *self, PyObject *args, PyObject *kwds)
                               MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (char*)&abool);
             }
 #endif
+          mysql_ssl_set(&self->session, ssl_key, ssl_cert, ssl_ca, NULL, NULL);
+        } else {
+          mysql_ssl_set(&self->session, ssl_key, ssl_cert, NULL, NULL, NULL); 
         }
-        mysql_ssl_set(&self->session, ssl_key, ssl_cert, ssl_ca, NULL, NULL);
     } else {
         // Make sure to not enforce SSL
 #if MYSQL_VERSION_ID > 50703 && MYSQL_VERSION_ID < 50711
@@ -1158,9 +1165,27 @@ MySQL_connect(MySQL *self, PyObject *args, PyObject *kwds)
 #endif
     }
 
+    Py_END_ALLOW_THREADS
     if (PyString_Check(self->auth_plugin)) {
         auth_plugin= PyStringAsString(self->auth_plugin);
         mysql_options(&self->session, MYSQL_DEFAULT_AUTH, auth_plugin);
+        if (strcmp(auth_plugin, "sha256_password") == 0 && !ssl_enabled)
+        {
+            PyObject *exc_type= MySQLInterfaceError;
+            PyObject *err_no= PyInt_FromLong(2002);
+            PyObject *err_msg= PyStringFromString("sha256_password requires SSL");
+            PyObject *err_obj= NULL;
+            err_obj= PyObject_CallFunctionObjArgs(exc_type, err_msg, NULL);
+            PyObject_SetAttr(err_obj, PyStringFromString("sqlstate"), Py_None);
+            PyObject_SetAttr(err_obj, PyStringFromString("errno"), err_no);
+            PyObject_SetAttr(err_obj, PyStringFromString("msg"), err_msg);
+            PyErr_SetObject(exc_type, err_obj);
+            Py_XDECREF(exc_type);
+            Py_XDECREF(err_no);
+            Py_XDECREF(err_msg);
+            return NULL;
+        }
+
         if (strcmp(auth_plugin, "mysql_clear_password") == 0)
         {
             abool= 1;
@@ -1168,6 +1193,7 @@ MySQL_connect(MySQL *self, PyObject *args, PyObject *kwds)
                           (char*)&abool);
         }
     }
+    Py_BEGIN_ALLOW_THREADS
 
     if (database && strlen(database) == 0)
     {
diff --git a/tests/cext/test_cext_api.py b/tests/cext/test_cext_api.py
index fff08ed..3a2cf74 100644
--- a/tests/cext/test_cext_api.py
+++ b/tests/cext/test_cext_api.py
@@ -529,6 +529,8 @@ class CExtMySQLTests(tests.MySQLConnectorTests):
         cmy1.set_character_set('big5')
         self.assertEqual(exp, get_variables(cmy1, variables=variables))
 
+    @unittest.skipIf(tests.MYSQL_VERSION == (5, 7, 4),
+                     "test_get_ssl_cipher not tested with MySQL version 5.7.4")
     def test_get_ssl_cipher(self):
         cmy1 = MySQL(buffered=True)
         self.assertRaises(MySQLInterfaceError, cmy1.get_ssl_cipher)
diff --git a/tests/cext/test_cext_cursor.py b/tests/cext/test_cext_cursor.py
index 2584c57..ea809ee 100644
--- a/tests/cext/test_cext_cursor.py
+++ b/tests/cext/test_cext_cursor.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -29,6 +29,7 @@ import logging
 import unittest
 
 from mysql.connector import errors, errorcode
+from .. import PY2
 
 import tests
 
@@ -516,6 +517,28 @@ class CExtMySQLCursorTests(tests.CMySQLCursorTests):
         cur.close()
         self.cnx.rollback()
 
+        cur = self._get_cursor(self.cnx)
+        cur.execute("DROP PROCEDURE IF EXISTS multi_results")
+        procedure = (
+            "CREATE PROCEDURE multi_results () "
+            "BEGIN SELECT 1; SELECT 'ham'; END"
+        )
+        cur.execute(procedure)
+        stmt = "CALL multi_results()"
+        if not PY2:
+            stmt = b"CALL multi_results()"
+        exp_result = [[(1,)], [(u'ham',)]]
+        results = []
+        for result in cur.execute(stmt, multi=True):
+            if result.with_rows:
+                self.assertEqual(stmt, result._executed)
+                results.append(result.fetchall())
+
+        self.assertEqual(exp_result, results)
+        cur.execute("DROP PROCEDURE multi_results")
+
+        cur.close()
+
 
 class CExtMySQLCursorBufferedTests(tests.CMySQLCursorTests):
 
diff --git a/tests/data/ssl/tests_CA_cert.pem b/tests/data/ssl/tests_CA_cert.pem
index b2032c0..6ce8c47 100644
--- a/tests/data/ssl/tests_CA_cert.pem
+++ b/tests/data/ssl/tests_CA_cert.pem
@@ -1,20 +1,19 @@
 -----BEGIN CERTIFICATE-----
-MIIDVzCCAj+gAwIBAgIJAIUsZ/vX9kOGMA0GCSqGSIb3DQEBBQUAMEIxJTAjBgNV
-BAsMHE15U1FMQ29ubmVjdG9yUHl0aG9uIFJvb3QgQ0ExGTAXBgNVBAMMEE15Q29u
-blB5IFJvb3QgQ0EwHhcNMTMwMzI2MTUzNTUyWhcNMjIwNDE0MTUzNTUyWjBCMSUw
-IwYDVQQLDBxNeVNRTENvbm5lY3RvclB5dGhvbiBSb290IENBMRkwFwYDVQQDDBBN
-eUNvbm5QeSBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
-qWcX9kD+b8c3hkPtPlIgwTsfGvhm/bJ64RHjCtQc2pi/fv9hlcryor8tWmdCCcw7
-ajg5n/QAIJ8crD5D0kheGEnWVI7dyVxZVfT3CiKuS+GBxuQP2ejJi4aDGh2McVv4
-aq1dXRqf2YWkM8PUjM0lzUD9MC9S4APtP6ux0TBhz5rv2ZWdg2EAjAl7Q56KM5m6
-odpF+Z1ExnfVpNzWnpvlYHJ+GhbVWb2F0NbqBTmz4OLEAxU/O2fo43dwVlHp+yNd
-ib2V+VxeeyZmTt1CIeK6DStAiKdNLN5/N/+2FHZ9/XcA6qqxLFLeuTIySlPmuaX6
-u2C8tmOWp99TCUL+GZ2iBwIDAQABo1AwTjAdBgNVHQ4EFgQU1objOGh5rgtBTmjK
-gPkN6SgXl64wHwYDVR0jBBgwFoAU1objOGh5rgtBTmjKgPkN6SgXl64wDAYDVR0T
-BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAWgHZzUo8oGP7YxMn9YACdbipTRYU
-IzGF+Cf0ueXktcEDbq7AIa6MsxXTp8pFOObvLiiecrMngYlqfHlYPL2HG+zOLDig
-nmkO4pGwTqCDZHO4aYBdiVMlaxSpxMX9R/kFYRP1P4AGLOp66FirNO5iLNlTIjpf
-PGebF+k0B1zUSUPsrZfa/d29XcJxBaw7aEOhARQYsymItasnTdcKvjZp1ahGnZYz
-yCDtJjVbXK/4qEtiSA4qcV1HrNuHmhZEwWahntLqo++x3oLK7DrWfHwTX5gHMyv2
-DGTggnNfB8uzzNe3giT0j6ie9DJEnvv1hB0GpUToUNECusrKsYnWLdJkIA==
+MIIDADCCAegCCQDmOCndJJOWFjANBgkqhkiG9w0BAQsFADBCMSUwIwYDVQQLDBxN
+eVNRTENvbm5lY3RvclB5dGhvbiBSb290IENBMRkwFwYDVQQDDBBNeUNvbm5QeSBS
+b290IENBMB4XDTE3MDMxNzE1NTAzNloXDTI2MDQwNTE1NTAzNlowQjElMCMGA1UE
+CwwcTXlTUUxDb25uZWN0b3JQeXRob24gUm9vdCBDQTEZMBcGA1UEAwwQTXlDb25u
+UHkgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANex2fME
+DGfFk6KIIjsCpXQ6Rsv7nClZ+H7iT/xBMDHtQbqVYX1HIDYGRApWIi0Mmg3hosri
+6TO5wJIMMEwcSurVStyLXPpCT4Dg3iDuKToYfNNGtuH9DFWh1fnkeni0gbEh+/yT
+PIe3FLZCHD+F12ST1z88i4LXOG4NuozKI2cmQcHxdVkYYzknMX4IKdP4AniPgMq0
+9YmQJjXH6y7lPzDXeUuG8YrOSuvfl4W2bjht4mGP6YUUQkwZ5qbRQfrkduQB3+pa
++7P6ckd3q91j1+H1kRCn4a1S28xzPOaey6cLQ/DRVKP9EwPVV9H3/Wm8BdTr0ZMs
+1s2VQtocmzcp35kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAGvUp9Du79gpN/pBD
+8eG7ZX/YMpK1cbzUwD+TqmP7QnXItRrZalbmadzZ6P161ff0QOEQPxL181+EEXFe
+yC8f33EGu9n6ZlSnj/HrdMZ2sjv8QA8M4Vg2vn81qUT/EsJQOjJA6n30ybncZHWB
+ovmFgBlq9miX2gDCMRosiRkzm4HAETdWQhiQ/jU4RV+pgP3/sd/mk/u2D5nqMeuT
+Ni61ke1CfskuCar5knXTdw7PYfCVXrD1ndgpf7e+qdz534GMkHcFKQkEvWE+ZuWj
+CHx9t32JFekCSzJCYs5YuAfuIJc0aC+RmA/lF7UUGyj++wWFAMnkmVEf5MM3WGjM
+HRerEg==
 -----END CERTIFICATE-----
diff --git a/tests/data/ssl/tests_CA_key.pem b/tests/data/ssl/tests_CA_key.pem
index bfccf21..1941850 100644
--- a/tests/data/ssl/tests_CA_key.pem
+++ b/tests/data/ssl/tests_CA_key.pem
@@ -1,27 +1,27 @@
 -----BEGIN RSA PRIVATE KEY-----
-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
+MIIEowIBAAKCAQEA17HZ8wQMZ8WToogiOwKldDpGy/ucKVn4fuJP/EEwMe1BupVh
+fUcgNgZEClYiLQyaDeGiyuLpM7nAkgwwTBxK6tVK3Itc+kJPgODeIO4pOhh800a2
+4f0MVaHV+eR6eLSBsSH7/JM8h7cUtkIcP4XXZJPXPzyLgtc4bg26jMojZyZBwfF1
+WRhjOScxfggp0/gCeI+AyrT1iZAmNcfrLuU/MNd5S4bxis5K69+XhbZuOG3iYY/p
+hRRCTBnmptFB+uR25AHf6lr7s/pyR3er3WPX4fWREKfhrVLbzHM85p7LpwtD8NFU
+o/0TA9VX0ff9abwF1OvRkyzWzZVC2hybNynfmQIDAQABAoIBAQDMZI2KuqBiyZhQ
+IT6Gusg8rmieLYzappZS7nQrLz7TYOezPpEGXRsJ9sANJ3f1RobJdrKEHagsyu3P
+t9sglILtqzbobOurfqDGGNCFVgodMk0/DDiLR/ajQtt4lOj1bt+jEfgubPukA3qO
+B3GrRFJKzcnf86ikUPv5VescNQR9Xca8qvy0W69SmtkSSZcC55yhWhGwReUDmywH
+tu57eR07t1Jf3RdHwa98VsiEde4TcuA/wo/C3e2A1MZZW0AtqVAVrX8hq+UVAMJ8
+sMubjNqUmDjbOOL4YkLbyR237uC6V6ejmWKEjMXAYUlNnpme1EcoimSL35hCjDVU
+H6MwhBiBAoGBAPNawx7lICj0qYJ3CSP5VMiiD7vTdDmtNPg6KFesZ2XKPALR/Csq
+1WXSEOb4DvFOAuSWjWYPW+0gvV966LkhKXE+cXWf4RmggrpwhT1JPbkcBwbwQ5oo
+aJnNByCcxoTBvJavLkrDBvZzOW2j5lvcD8qfnNYtbNihsExzkxfFm7AxAoGBAOLn
+JJqLwuNK2cyi7F5mkRLhGCdtSglSoht/3xTuqdrQv0JsVjmGTOqZhh6EBeI91auu
+O89KLs2ARN/KKR90ckuf/h6iwsS5/PDjiPTWOcH8LjiocPuvtvoRzq6leoC1XWBm
+vqLZYjPGuZRNibvputUFIVprw38EmppZzcrBuPPpAoGAa1mIZWKRsz9qX0D/aT0d
+p3vGEQcQaDj9+to83aAR5Jc3rc7PvIMiq83k4t5eSRgusoOvUGxKEuq0XyAq9S+p
+xmjTSB4FAHcL9A6a2BQtBDFW8Dqgt6pHqkEFed9uuzVzac1RUG2D7seZd8IrZi5H
+UQzj9J8JOu7ohHEfXAcxzKECgYA9mJ/wMGasi0JK8iOWkONrK54B/gIuO7d0Hady
+qEOF+kshfgV+Qj4ZJaoqGI78VurtWzQzVqET+nE4C0pUlqj8bKdwq6CSBSdsQWiJ
+hqpRReNKUDezq4TRqAnikVuLGzEJHXs8/CRTh+wTHWV5lL66W1UtlbmRfq91nVFn
+bGWIGQKBgE3S/0XsB9Ox+lNyxj5TycmT9VEfn+vvB+PF3ITWLRkcDanK5ynh4Pvt
+2HbwWIShQXGczn4jzWX61AwWE7Lkc1an1yiCQ2/SJItyhWJxVGO0V0BwTK9jmq+r
+1DXQSTgsOtmRknMdgGTk594Nj7S4r4GDYudzAujsbsrPEItw2nRr
 -----END RSA PRIVATE KEY-----
diff --git a/tests/data/ssl/tests_client_cert.pem b/tests/data/ssl/tests_client_cert.pem
index 82fcf77..05ae516 100644
--- a/tests/data/ssl/tests_client_cert.pem
+++ b/tests/data/ssl/tests_client_cert.pem
@@ -1,18 +1,67 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number: 3 (0x3)
+    Signature Algorithm: md5WithRSAEncryption
+        Issuer: OU=MySQLConnectorPython Root CA, CN=MyConnPy Root CA
+        Validity
+            Not Before: Mar 17 15:50:37 2017 GMT
+            Not After : Mar 17 15:50:37 2018 GMT
+        Subject: OU=MySQLConnectorPython Client Cert, CN=localhost
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:b0:7b:da:61:20:7c:13:97:fa:1e:20:83:e0:40:
+                    e8:94:4a:ea:1c:62:22:09:4e:d3:cd:30:66:73:28:
+                    f4:ff:2d:79:a4:b6:0b:c7:b7:20:c8:f6:c0:98:66:
+                    3d:46:ec:f1:8c:04:8b:d7:3c:b4:fa:69:6c:c5:47:
+                    1b:04:a4:a3:53:5a:0a:f2:a4:f7:94:d5:2c:d7:b6:
+                    24:81:e0:c2:ea:51:d1:6e:8e:d4:58:dc:5b:fc:b9:
+                    1b:6b:7c:52:cc:17:36:85:63:ca:f0:1f:75:2f:b8:
+                    97:96:d1:08:ab:46:31:31:e6:9c:8b:26:a1:1b:df:
+                    35:66:36:d9:ba:e1:a4:3d:88:25:7a:9d:68:d3:62:
+                    20:ec:14:b0:59:2c:33:40:11:cf:03:70:17:1c:de:
+                    65:ca:0c:2e:26:2d:f0:33:13:52:d7:0f:69:d7:c0:
+                    d6:f8:71:03:19:f4:79:3d:66:98:56:d2:44:db:bf:
+                    aa:a7:d6:fc:2d:0b:29:63:0a:d4:3d:5e:7e:a7:2c:
+                    6c:b8:2f:32:6f:51:ce:4a:2d:6a:35:54:21:33:76:
+                    a2:64:4a:8c:1d:30:73:47:3e:90:19:68:c9:07:8f:
+                    14:c5:ff:93:c7:ec:b4:08:d7:30:11:f6:67:3f:7a:
+                    8a:57:2c:87:63:34:ff:ff:79:2b:6b:70:88:21:ca:
+                    4e:53
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: md5WithRSAEncryption
+         2e:d2:37:97:8b:aa:05:47:8d:b4:c6:87:7d:b8:41:d6:55:12:
+         84:14:8d:91:de:4f:84:15:89:a2:90:5a:0a:94:a1:c2:41:42:
+         18:3c:b7:10:c7:19:b5:01:96:2e:51:83:14:2f:64:0a:96:bb:
+         ce:f8:28:df:ab:fe:72:05:e8:6a:fd:1d:7b:09:22:eb:26:e7:
+         64:a7:a7:fe:fb:e8:e0:2f:91:e4:9e:fa:f6:ab:0b:5b:f3:82:
+         e0:54:d5:07:d2:05:ae:99:fd:22:d8:23:ba:e5:16:21:d7:b0:
+         82:98:4a:f0:87:36:ca:1e:4e:c0:c3:6a:22:a4:37:18:5f:6f:
+         6f:7b:92:e9:bb:15:77:55:6b:9a:57:35:95:4c:64:e9:bb:12:
+         cb:ab:67:4b:23:27:41:d3:71:15:5e:cf:6b:d6:13:05:f0:7a:
+         df:0f:f9:fd:bc:0d:8b:e4:cb:e7:62:67:9e:10:00:c9:9d:ea:
+         a7:cb:3f:ec:47:04:06:96:7f:b3:74:be:3c:cc:bd:72:05:d8:
+         91:b7:d6:b1:9a:40:79:bd:eb:cb:7a:49:bc:a6:e7:61:4f:1d:
+         68:79:21:ad:18:f6:13:6e:87:b6:13:a6:31:1e:f9:73:4c:ec:
+         04:b4:f2:83:5a:25:ae:9c:2e:8e:3a:0a:1d:0a:fd:34:dd:d4:
+         12:cc:4f:47
 -----BEGIN CERTIFICATE-----
-MIIC9TCCAd0CAQEwDQYJKoZIhvcNAQEFBQAwQjElMCMGA1UECwwcTXlTUUxDb25u
+MIIC9TCCAd0CAQMwDQYJKoZIhvcNAQEEBQAwQjElMCMGA1UECwwcTXlTUUxDb25u
 ZWN0b3JQeXRob24gUm9vdCBDQTEZMBcGA1UEAwwQTXlDb25uUHkgUm9vdCBDQTAe
-Fw0xMzAzMjYxNTM1NTJaFw0yMjA0MTQxNTM1NTJaMD8xKTAnBgNVBAsMIE15U1FM
+Fw0xNzAzMTcxNTUwMzdaFw0xODAzMTcxNTUwMzdaMD8xKTAnBgNVBAsMIE15U1FM
 Q29ubmVjdG9yUHl0aG9uIENsaWVudCBDZXJ0MRIwEAYDVQQDDAlsb2NhbGhvc3Qw
-ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDXbL7sr/k/W4LwwzTKJj5i
-1QtcZL0tMyBhAwuI7XQVyJBVvY7dRUM+G30ADOcUw5DscYbkkVu3L2NtsnmuyB8o
-0Y5bbHpTv4xTrVfsQuDkMLe+/LwFfL7XrY1Bm13xdEn345b6edfvhre7eatCgIaG
-IKfFr5JDv5oN4faGEJpqYahE/WdxM7zv6xb7Wx+yqLlezldU34VcLcghi8zfDkxb
-Fb4cZSgko/9RT7lTUGBJSSgITnq3Re0qANah7UbqFkTM2wfltoXGerbWMYuzOfQo
-5r0FiScjuvACkDALHAdUbX4UbXasArqpGovyVqHp4OWu3FWRfcCUnxAxfj3G3x79
-AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAFi+U6Fyc1L0qCTCiMvUMQuXacnOMH4q
-rHm7qDKkHHcMMGsspNXvLcVKEwJrX3dhP3dZ52eKyFsOjuTkO9eU5H8V2alO8iGD
-Zb6vHT/pQRInoc39SVDFx1QnJ7RlC2Z99xzncHMQChSlDCC+Lft/K5am7vXFwQ3e
-icfLqmR5hz6nc+opnPc7WbQu/cc7PesP5uroyKScYoqAiDJ2cKQJQFPM4Cvt/KZ3
-22H/yCyQNkplIcrlQRF+l+sInNlJZr36INF0o91GcucyuLQzOXUn0L5eAyFzA9RQ
-8xkVztqRN++CgbGAhqIt8ERBtxBvCpNxuFpgm4dPKCTLm+r7fJcKwDI=
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwe9phIHwTl/oeIIPgQOiU
+SuocYiIJTtPNMGZzKPT/LXmktgvHtyDI9sCYZj1G7PGMBIvXPLT6aWzFRxsEpKNT
+WgrypPeU1SzXtiSB4MLqUdFujtRY3Fv8uRtrfFLMFzaFY8rwH3UvuJeW0QirRjEx
+5pyLJqEb3zVmNtm64aQ9iCV6nWjTYiDsFLBZLDNAEc8DcBcc3mXKDC4mLfAzE1LX
+D2nXwNb4cQMZ9Hk9ZphW0kTbv6qn1vwtCyljCtQ9Xn6nLGy4LzJvUc5KLWo1VCEz
+dqJkSowdMHNHPpAZaMkHjxTF/5PH7LQI1zAR9mc/eopXLIdjNP//eStrcIghyk5T
+AgMBAAEwDQYJKoZIhvcNAQEEBQADggEBAC7SN5eLqgVHjbTGh324QdZVEoQUjZHe
+T4QViaKQWgqUocJBQhg8txDHGbUBli5RgxQvZAqWu874KN+r/nIF6Gr9HXsJIusm
+52Snp/776OAvkeSe+varC1vzguBU1QfSBa6Z/SLYI7rlFiHXsIKYSvCHNsoeTsDD
+aiKkNxhfb297kum7FXdVa5pXNZVMZOm7EsurZ0sjJ0HTcRVez2vWEwXwet8P+f28
+DYvky+diZ54QAMmd6qfLP+xHBAaWf7N0vjzMvXIF2JG31rGaQHm968t6Sbym52FP
+HWh5Ia0Y9hNuh7YTpjEe+XNM7AS08oNaJa6cLo46Ch0K/TTd1BLMT0c=
 -----END CERTIFICATE-----
diff --git a/tests/data/ssl/tests_client_key.pem b/tests/data/ssl/tests_client_key.pem
index 3c2b5c9..787bd4b 100644
--- a/tests/data/ssl/tests_client_key.pem
+++ b/tests/data/ssl/tests_client_key.pem
@@ -1,27 +1,27 @@
 -----BEGIN RSA PRIVATE KEY-----
-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
+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
 -----END RSA PRIVATE KEY-----
diff --git a/tests/data/ssl/tests_expired_server_cert.pem b/tests/data/ssl/tests_expired_server_cert.pem
new file mode 100644
index 0000000..cfba302
--- /dev/null
+++ b/tests/data/ssl/tests_expired_server_cert.pem
@@ -0,0 +1,68 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number: 2 (0x2)
+    Signature Algorithm: md5WithRSAEncryption
+        Issuer: OU=MySQLConnectorPython Root CA, CN=MyConnPy Root CA
+        Validity
+            Not Before: Aug 15 08:00:00 2012 GMT
+            Not After : Aug 15 09:00:00 2012 GMT
+        Subject: OU=MySQLConnectorPython Expired Server Cert, CN=localhost
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:df:5a:5b:72:42:5f:46:e5:bb:6c:e5:76:2e:6f:
+                    fd:b8:10:2f:04:10:55:43:0c:bf:af:f1:eb:f0:4f:
+                    6f:6b:d9:61:9f:2a:39:35:2d:cc:0c:05:5c:88:cc:
+                    98:a3:5c:78:9e:8c:6b:ba:33:3f:f2:46:96:f2:bb:
+                    78:63:ca:bd:72:2c:70:34:56:8b:12:e5:e9:ff:82:
+                    d5:50:bb:28:c2:99:83:af:3f:f1:67:77:b4:41:66:
+                    79:ee:f7:3a:93:8c:55:da:c3:d5:3a:44:40:82:e8:
+                    fa:4c:11:a7:13:20:31:78:48:1d:2e:95:8c:0f:4c:
+                    ea:ac:96:9d:9e:2a:37:c5:7a:42:f2:b1:8f:9b:15:
+                    69:9d:1c:19:26:69:84:a9:c6:9e:08:65:c0:7c:bf:
+                    72:a7:b0:ae:60:78:ad:7d:ea:0b:ed:ff:45:fc:24:
+                    56:f5:c6:f4:b5:00:0f:90:76:3e:52:08:ec:06:c4:
+                    30:51:66:60:f9:c6:0b:b9:f2:96:6a:c2:39:b8:b7:
+                    48:b8:3f:02:26:b5:95:f8:55:8d:d3:23:f1:dc:d0:
+                    ab:2c:05:3b:b5:99:4d:9a:81:78:27:60:0d:da:2e:
+                    23:e8:38:26:0b:6d:6c:f6:fd:a7:42:95:4c:d2:a5:
+                    7c:05:13:21:7b:c7:6d:ca:f1:e3:3d:ad:d4:32:79:
+                    5a:d3
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: md5WithRSAEncryption
+         36:e4:ba:6c:3b:99:29:ba:33:8b:da:ef:07:b8:7e:f6:07:b6:
+         79:7b:c7:b2:0c:0c:48:ff:52:25:05:34:f4:d9:f6:0a:0c:77:
+         10:a7:e5:40:f4:47:bf:4c:06:7b:8a:22:53:5a:91:dd:75:32:
+         d3:58:97:4f:d4:01:e8:b5:8d:ca:52:23:7f:72:1b:e2:c5:9a:
+         89:a4:be:e4:17:9b:fa:1f:c0:26:93:5f:c2:d2:1b:e0:c2:9e:
+         36:d1:3f:95:bd:6f:af:cd:f3:8f:6a:c6:5c:b0:6b:ae:07:60:
+         59:be:fa:fd:f8:43:5b:20:38:02:b8:a6:f5:eb:35:be:46:55:
+         7b:84:9f:e5:cb:5d:6b:af:2a:28:d1:af:32:1f:e3:71:d8:f8:
+         96:4a:f1:88:f3:10:27:ed:c5:a2:65:f4:b5:2b:58:77:93:25:
+         e7:36:e1:4b:cb:18:10:cd:81:fc:80:e6:24:0f:27:4c:33:22:
+         af:36:88:ee:f8:0d:ef:ff:47:74:87:50:e8:ea:03:da:71:a1:
+         65:fd:00:8c:c8:a8:27:fa:e0:40:43:60:8f:aa:1f:25:4f:05:
+         d7:a5:fe:9b:a3:82:90:0b:50:bf:bd:62:a3:9e:14:20:80:18:
+         8b:8c:5e:f7:97:b8:b7:a5:63:d8:22:1a:98:6c:32:da:38:7b:
+         fc:e6:2c:f3
+-----BEGIN CERTIFICATE-----
+MIIC/TCCAeUCAQIwDQYJKoZIhvcNAQEEBQAwQjElMCMGA1UECwwcTXlTUUxDb25u
+ZWN0b3JQeXRob24gUm9vdCBDQTEZMBcGA1UEAwwQTXlDb25uUHkgUm9vdCBDQTAe
+Fw0xMjA4MTUwODAwMDBaFw0xMjA4MTUwOTAwMDBaMEcxMTAvBgNVBAsMKE15U1FM
+Q29ubmVjdG9yUHl0aG9uIEV4cGlyZWQgU2VydmVyIENlcnQxEjAQBgNVBAMMCWxv
+Y2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN9aW3JCX0bl
+u2zldi5v/bgQLwQQVUMMv6/x6/BPb2vZYZ8qOTUtzAwFXIjMmKNceJ6Ma7ozP/JG
+lvK7eGPKvXIscDRWixLl6f+C1VC7KMKZg68/8Wd3tEFmee73OpOMVdrD1TpEQILo
++kwRpxMgMXhIHS6VjA9M6qyWnZ4qN8V6QvKxj5sVaZ0cGSZphKnGnghlwHy/cqew
+rmB4rX3qC+3/RfwkVvXG9LUAD5B2PlII7AbEMFFmYPnGC7nylmrCObi3SLg/Aia1
+lfhVjdMj8dzQqywFO7WZTZqBeCdgDdouI+g4JgttbPb9p0KVTNKlfAUTIXvHbcrx
+4z2t1DJ5WtMCAwEAATANBgkqhkiG9w0BAQQFAAOCAQEANuS6bDuZKbozi9rvB7h+
+9ge2eXvHsgwMSP9SJQU09Nn2Cgx3EKflQPRHv0wGe4oiU1qR3XUy01iXT9QB6LWN
+ylIjf3Ib4sWaiaS+5Beb+h/AJpNfwtIb4MKeNtE/lb1vr83zj2rGXLBrrgdgWb76
+/fhDWyA4Arim9es1vkZVe4Sf5ctda68qKNGvMh/jcdj4lkrxiPMQJ+3FomX0tStY
+d5Ml5zbhS8sYEM2B/IDmJA8nTDMirzaI7vgN7/9HdIdQ6OoD2nGhZf0AjMioJ/rg
+QENgj6ofJU8F16X+m6OCkAtQv71io54UIIAYi4xe95e4t6Vj2CIamGwy2jh7/OYs
+8w==
+-----END CERTIFICATE-----
diff --git a/tests/data/ssl/tests_expired_server_key.pem b/tests/data/ssl/tests_expired_server_key.pem
new file mode 100644
index 0000000..6b68fe2
--- /dev/null
+++ b/tests/data/ssl/tests_expired_server_key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA31pbckJfRuW7bOV2Lm/9uBAvBBBVQwy/r/Hr8E9va9lhnyo5
+NS3MDAVciMyYo1x4noxrujM/8kaW8rt4Y8q9cixwNFaLEuXp/4LVULsowpmDrz/x
+Z3e0QWZ57vc6k4xV2sPVOkRAguj6TBGnEyAxeEgdLpWMD0zqrJadnio3xXpC8rGP
+mxVpnRwZJmmEqcaeCGXAfL9yp7CuYHitfeoL7f9F/CRW9cb0tQAPkHY+UgjsBsQw
+UWZg+cYLufKWasI5uLdIuD8CJrWV+FWN0yPx3NCrLAU7tZlNmoF4J2AN2i4j6Dgm
+C21s9v2nQpVM0qV8BRMhe8dtyvHjPa3UMnla0wIDAQABAoIBAC7IP0U0b75q2hIa
+EeHyJSOLiD2Cqkkr/2577p5cFQty8caj0m24FPgjm1kv+XymHsGeyeWrXGaDsJRQ
+/gtw6LNkaXAc/G5N5/BT2Bhby1LPUsy/SPISGZhlPX73G7bR+x2iTSQyLYz9/Yc3
+X1ZbNOFrwWkDe92sj67ssUDyuNHMwLpw35/OWX2W7YsGzi7j2zbZdmhp2c3E0/bD
+NL2217BsPMLD1/f0og6Ix9kvSt+2Z3XW6RlhP7LDNDRI7F8oRRVvYgQGHBHibvlG
+I4n07lycLo0dPsc08PcUvJ5UyhI7VYk/MZACLNhrjgPxYz1HdL7deVoQbW6z4q19
+g1JjI2kCgYEA+eOIvGkz9wga74VVKMZIqXPaMmccNkwbzUb7Ay1CM50pdYLk6E6R
+LdEIx0/qQC8Zpw47NhSFzZT8sakHqmK7VIJRdMJWSTKu/4QMooigRasFJXPWwJVa
+LsTE1gg3LGL+RkuoQNIlPle6nTGcCLGfnB8Js1GA3/SunFQCoJr+stcCgYEA5NCx
+BSmZz07Rso3FWzRMjR52m2JDWvMm4+eU/HxXGrPdYfBQEowxzesORRBRIlp8Z5ki
+929ayJ5qONLjMFx1l/QguT9BNkbzO3gpbH3/G187wFQ0v8jXmDRjU7ftgyL6PAD+
+eJsj39+TfA+Hua6m6VkLH5XUpy3Vl8nBkM2cFGUCgYEAl1zEiWOsD1lAf48i2zTn
+9IRxSZB9XUJSoM/64Zy7eeobn8tufmyAseDpUVlNyhz9i9wp74MU3Ub+nVqGgyWU
+1Qau8mt4upPRvoIs6RKbCjgiQOJe1X5iBuw3UnHdgaxg2xGe08y2tIGNTwQqwHVe
++cEvLggTaRSb46NbiA76cjcCgYBGkWZG5VGecfySSM75FeQWEbMasO98+UihOSbl
+x6NFhPtd3TOUxNAHZdr8yc97/NQpTz1NenZRMSopZEDVBW7u8ke1WiDOkIsraB++
+ag1nb7OJ2W57R4HWWzHW+/6wVvU91ECnCZHC1b0yoceGKKsphGC92QPAm44oRf0A
+n6jnUQKBgD0MqIjngDIRMwGpkXpsJJDt9/dw6izz3sWhBDkBLKCt63nwT3pykDDF
+qJ8dq9TSGwO6H1c/obKdFlx53PBDUpZV9txI8ScF2YNlfs3Ts4+oElkU/jCMJPKi
+M73I0Jgg+GwToDcjC4d7oREIBlfXjBLBjCcHx1315NMUW42QkrNo
+-----END RSA PRIVATE KEY-----
diff --git a/tests/data/ssl/tests_server_cert.pem b/tests/data/ssl/tests_server_cert.pem
index dc7938c..3276dea 100644
--- a/tests/data/ssl/tests_server_cert.pem
+++ b/tests/data/ssl/tests_server_cert.pem
@@ -1,18 +1,67 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number: 1 (0x1)
+    Signature Algorithm: md5WithRSAEncryption
+        Issuer: OU=MySQLConnectorPython Root CA, CN=MyConnPy Root CA
+        Validity
+            Not Before: Mar 17 15:50:37 2017 GMT
+            Not After : Mar 17 15:50:37 2018 GMT
+        Subject: OU=MySQLConnectorPython Server Cert, CN=localhost
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:a3:0d:e6:bd:d7:5e:1e:0f:b2:0a:83:43:50:fe:
+                    7c:bc:32:dc:04:fd:38:97:86:1e:e0:9c:46:08:65:
+                    ac:76:6f:0d:93:33:31:4e:02:8a:a7:e9:9a:b9:4f:
+                    f9:d3:66:56:29:1a:e5:0f:df:7b:61:e5:3c:06:db:
+                    ea:cd:d6:71:9d:63:b2:f9:e1:c1:ed:9a:6e:2f:2f:
+                    be:94:76:aa:ee:24:b3:58:f0:82:25:00:ef:c8:19:
+                    4f:15:6f:f2:3b:b4:e4:9b:0d:36:c7:17:39:7d:35:
+                    45:e8:76:62:94:19:ab:64:d8:89:78:75:92:29:e2:
+                    35:79:dd:e1:bf:3f:52:bf:ef:4c:d1:c1:fc:d0:a6:
+                    ee:b8:01:39:26:28:67:40:73:46:5e:55:65:3b:56:
+                    c9:c0:e1:7a:a4:a1:0c:46:d2:1e:b3:af:c5:cc:5b:
+                    07:81:79:c5:d0:44:57:ed:ea:ad:d9:c2:45:70:72:
+                    46:d3:e2:a3:f4:d0:49:33:ac:66:89:9b:83:65:f9:
+                    92:07:4e:9c:bf:b0:59:90:f8:35:8f:19:d2:82:d7:
+                    49:46:f5:4b:6a:c0:bd:5c:5d:0f:a0:fb:29:15:a7:
+                    68:5e:e1:48:20:c8:14:eb:fc:17:29:d6:95:4a:27:
+                    70:f3:c3:52:3d:1c:a5:d4:cf:3c:87:81:d7:d9:bb:
+                    dc:49
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: md5WithRSAEncryption
+         36:58:2f:f4:95:e6:8b:ef:5b:59:91:2e:31:c2:21:64:b7:ac:
+         e6:bf:4e:b7:12:06:7d:8b:74:eb:82:88:65:00:4c:12:5e:6b:
+         dd:8b:d5:5e:cd:74:92:8a:dd:eb:fb:5b:1d:46:b0:e4:7d:55:
+         1a:01:9a:82:0c:4d:91:05:e2:92:f5:17:0f:a5:8b:d9:8e:8f:
+         17:55:19:83:07:2b:ea:2b:16:15:30:f7:31:7e:84:cc:b7:e0:
+         b1:b1:53:5d:e9:40:87:19:98:d5:f8:eb:ae:ef:b4:e7:85:12:
+         38:e7:12:f4:44:03:08:a6:fc:3b:aa:26:1c:52:95:e0:7b:93:
+         92:00:e2:21:b8:09:00:7d:e5:08:b4:c8:53:1d:2c:11:ea:86:
+         5c:f9:14:c6:3f:73:0a:bc:e7:96:cb:e9:39:23:d7:50:0f:7d:
+         2e:04:be:e9:5b:0b:bf:99:85:8c:ed:32:14:1d:09:c5:d5:d1:
+         e6:db:f2:54:51:3f:5f:0e:e0:06:58:c8:52:68:4e:39:25:bd:
+         b5:1b:8b:b2:1d:95:cb:cb:22:18:b5:d7:27:3d:32:c4:79:c4:
+         fa:e1:6f:00:1c:63:da:4a:ce:9e:de:0c:a4:dd:bd:d3:d6:cb:
+         51:d7:e6:32:5f:5f:31:1f:a5:9d:5f:d5:2c:21:72:a7:ed:f1:
+         d8:31:c8:b4
 -----BEGIN CERTIFICATE-----
-MIIC9TCCAd0CAQEwDQYJKoZIhvcNAQEFBQAwQjElMCMGA1UECwwcTXlTUUxDb25u
+MIIC9TCCAd0CAQEwDQYJKoZIhvcNAQEEBQAwQjElMCMGA1UECwwcTXlTUUxDb25u
 ZWN0b3JQeXRob24gUm9vdCBDQTEZMBcGA1UEAwwQTXlDb25uUHkgUm9vdCBDQTAe
-Fw0xMzAzMjYxNTM1NTJaFw0yMjA0MTQxNTM1NTJaMD8xKTAnBgNVBAsMIE15U1FM
+Fw0xNzAzMTcxNTUwMzdaFw0xODAzMTcxNTUwMzdaMD8xKTAnBgNVBAsMIE15U1FM
 Q29ubmVjdG9yUHl0aG9uIFNlcnZlciBDZXJ0MRIwEAYDVQQDDAlsb2NhbGhvc3Qw
-ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDv6WQ/Ssum4RchjXSlwbcB
-au3WNccfodThBOAM27AOnJQWIjG4e5s9H7lLznI+VF5MgUbgbp/yz4D+CrSFvLgU
-4xxzd1/SVbnzRJ5iD2EmaZPjoMkBmvDRd4ow6IdFN80Fpwxij6fUBHdRkyXyiYsG
-FE94PQCyD1R47LSubd/gfcjXw8Bt5cWqcopiolZ01bYuMzeZIw0et9gf6Iih2Zh1
-bs9RthHfL3BfN4knljF3XmRQhfsc4w3MvdulX4mcfzS+E+keOOgPjfjo9KVCD1Zl
-F00wQdbSCWzf9uCP4OpKJGURyMQEmGMFPBOP98kqns1CqaE0PxKOpbcTX86nSEO5
-AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAFy4ONx0zFYgVNL046lfRmimyRf1gbmB
-pyyug9eW6QuuTfqbzFWOYZY8pG2lzKnHNUMmgzMNMpiRLRJ38Dj5rApg+7OkiTT+
-l4DMIR/YblJryEvx6tNUq2Cu9GXKW2qrGJO3XVniuBpmg1srugdwyxS+LdFofgBc
-I4cKIDuXYATUpOFhEsFbMY6tGVeOXQN2jSWtUj6+mKiUWMyr+5NYD8xhjDV7q4GH
-JfQqWFzw7prtSYzwB8lc0PM2SLwxeE9cQUYN/UkW8HRxM7Ft5KyyXUk+2Jg61sZ2
-QxMCV6NAGYMX40WRDqIZbs9AbHWoCxEwoXWtcmNb0GInsk39lFMJqw4=
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCjDea9114eD7IKg0NQ/ny8
+MtwE/TiXhh7gnEYIZax2bw2TMzFOAoqn6Zq5T/nTZlYpGuUP33th5TwG2+rN1nGd
+Y7L54cHtmm4vL76UdqruJLNY8IIlAO/IGU8Vb/I7tOSbDTbHFzl9NUXodmKUGatk
+2Il4dZIp4jV53eG/P1K/70zRwfzQpu64ATkmKGdAc0ZeVWU7VsnA4XqkoQxG0h6z
+r8XMWweBecXQRFft6q3ZwkVwckbT4qP00EkzrGaJm4Nl+ZIHTpy/sFmQ+DWPGdKC
+10lG9UtqwL1cXQ+g+ykVp2he4UggyBTr/Bcp1pVKJ3Dzw1I9HKXUzzyHgdfZu9xJ
+AgMBAAEwDQYJKoZIhvcNAQEEBQADggEBADZYL/SV5ovvW1mRLjHCIWS3rOa/TrcS
+Bn2LdOuCiGUATBJea92L1V7NdJKK3ev7Wx1GsOR9VRoBmoIMTZEF4pL1Fw+li9mO
+jxdVGYMHK+orFhUw9zF+hMy34LGxU13pQIcZmNX4667vtOeFEjjnEvREAwim/Duq
+JhxSleB7k5IA4iG4CQB95Qi0yFMdLBHqhlz5FMY/cwq855bL6Tkj11APfS4Evulb
+C7+ZhYztMhQdCcXV0ebb8lRRP18O4AZYyFJoTjklvbUbi7IdlcvLIhi11yc9MsR5
+xPrhbwAcY9pKzp7eDKTdvdPWy1HX5jJfXzEfpZ1f1Swhcqft8dgxyLQ=
 -----END CERTIFICATE-----
diff --git a/tests/data/ssl/tests_server_key.pem b/tests/data/ssl/tests_server_key.pem
index 13c39fe..466fc97 100644
--- a/tests/data/ssl/tests_server_key.pem
+++ b/tests/data/ssl/tests_server_key.pem
@@ -1,27 +1,27 @@
 -----BEGIN RSA PRIVATE KEY-----
-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
+MIIEpQIBAAKCAQEAow3mvddeHg+yCoNDUP58vDLcBP04l4Ye4JxGCGWsdm8NkzMx
+TgKKp+mauU/502ZWKRrlD997YeU8BtvqzdZxnWOy+eHB7ZpuLy++lHaq7iSzWPCC
+JQDvyBlPFW/yO7Tkmw02xxc5fTVF6HZilBmrZNiJeHWSKeI1ed3hvz9Sv+9M0cH8
+0KbuuAE5JihnQHNGXlVlO1bJwOF6pKEMRtIes6/FzFsHgXnF0ERX7eqt2cJFcHJG
+0+Kj9NBJM6xmiZuDZfmSB06cv7BZkPg1jxnSgtdJRvVLasC9XF0PoPspFadoXuFI
+IMgU6/wXKdaVSidw88NSPRyl1M88h4HX2bvcSQIDAQABAoIBAQCU+Epr/6x5gpWD
+jVGfWiLUPxNNa5ycs2jahWxml53txqB8cDUHtMLBjmhSDoONZN4rR+sniWLMmgcx
+rRLlZJsA1Onb6yqmzoUEj3ZrZc/dK6LAC1ycOjLYemcKivChJDAIiRYW510ay+VG
+8YI3FQzGYh+W8rPLmGSLJvDtLgmIWMBavXi5hhErRSotsqAICLzfhnlKbFMc12ZS
+b+eYX3/Q/NQlOKHtIhChEpvm1McYOhb4+8UI0Opc1LfQOE0qcgL9upEp2UK5qUCP
+71dIwVgTMp0VyA2StkPzV+wu0pl1hFUfHlZE7B8oJrkUhLzT61+RzMmeXAMrw31A
+PiP+kd2RAoGBAM489b23ioAIUiqswMy1PETYjNJvaxZ2eVk+2fyvGRw9wDWDAupi
++gfcV1cBRn29OINrW7AhobCpBZcqGyvBxtcq+EZxSFIZOqioNPHyANScLg0ijHku
+02lPc6jHedqj4B+gU6dWq7kDuExiV/idIrb0oTPHVo+e1sw+/WGVEJcjAoGBAMpl
+iYRHr1yASL8BjOVRzNUxbAxNccYHi1R5MimAQzotTQEQxHVoxedtzEiGO0sGl1ce
+gdgGAtKBCMXjiC09vEvYO/ocOxVDKmGi5sVvQvTizTdi3HNf4E1kEGnZDG4ZiqEP
+vSGsZPTq9XoLPraQw9xd3BsYOAOJUHVUWsiLAGujAoGAfN5r63I1aU+gcDYohck1
+tHloygCr1e3liyOC2HsruO2qcrvgCAnlWN0QBJ3BEGCA1xEpcnrqawvrVpsn2FZ7
+Dcv2hrAQGaUs3vD5HYRo/FGTkGBarQSs/BYe8RHVtYuDJ6LrA2Z2ko6uB5GDsgNy
+AVQcRj1rK4oAg6mfwHWAlgECgYEAg7ydSqViJeI192Up8SVSHr4BZuyNjmjgroYI
+OW0L1PUhdv0T8pvUnLMh0V7Vfxr2LLVlrFcVRTDJpgxYWaIiSnefakcvycIi9tQS
+QxYNTdnF2zQU61/PXnAwIsUsywkC65yT7TQJrkS0rNBe7HPDmE7bciNMajjZTtUu
+FfQrvOMCgYEAojKV9hEJxvkwIMD7D6lvCpaMdMmv7yxgMbuNJ6je9h3faKc8tKQK
+4d5F1Cl/CKXQcwSMt0IDy3jynJJDP8bN3Wp1C8lU8ZnzoGbGK2jotGtjG6UaOL7B
+N4BnlJGjJUqYni2xRWk8A+/HT5zngN0Q7+Eq0vkdajewjISKiH4reaA=
 -----END RSA PRIVATE KEY-----
diff --git a/tests/mysqld.py b/tests/mysqld.py
index 6d6463d..e007361 100644
--- a/tests/mysqld.py
+++ b/tests/mysqld.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -343,9 +343,10 @@ class MySQLServerBase(object):
 class MySQLServer(MySQLServerBase):
     """Class for managing a MySQL server"""
 
-    def __init__(self, basedir, topdir, cnf, bind_address, port,
-                 name, datadir=None, tmpdir=None,
-                 unix_socket_folder=None, ssl_folder=None, sharedir=None):
+    def __init__(self, basedir, topdir, cnf, bind_address, port, name,
+                 datadir=None, tmpdir=None, unix_socket_folder=None,
+                 ssl_folder=None, ssl_ca=None, ssl_cert=None, ssl_key=None,
+                 sharedir=None):
         self._cnf = cnf
         self._option_file = os.path.join(topdir, 'my.cnf')
         self._bind_address = bind_address
@@ -353,6 +354,9 @@ class MySQLServer(MySQLServerBase):
         self._topdir = topdir
         self._basedir = basedir
         self._ssldir = ssl_folder or topdir
+        self._ssl_ca = os.path.join(self._ssldir, ssl_ca)
+        self._ssl_cert = os.path.join(self._ssldir, ssl_cert)
+        self._ssl_key = os.path.join(self._ssldir, ssl_key)
         self._datadir = datadir or os.path.join(topdir, 'data')
         self._tmpdir = tmpdir or os.path.join(topdir, 'tmp')
         self._name = name
@@ -540,13 +544,7 @@ class MySQLServer(MySQLServerBase):
         """Return the unix socket of the server"""
         return self._unix_socket
 
-    def start(self):
-        """Start a MySQL server"""
-        if self.check_running():
-            LOGGER.error("MySQL server '{name}' already running".format(
-                name=self.name))
-            return
-
+    def update_config(self, **kwargs):
         options = {
             'name': self._name,
             'basedir': _convert_forward_slash(self._basedir),
@@ -555,16 +553,31 @@ class MySQLServer(MySQLServerBase):
             'bind_address': self._bind_address,
             'port': self._port,
             'unix_socket': _convert_forward_slash(self._unix_socket),
-            'ssl_dir': _convert_forward_slash(self._ssldir),
+            'ssl_ca': _convert_forward_slash(self._ssl_ca),
+            'ssl_cert': _convert_forward_slash(self._ssl_cert),
+            'ssl_key': _convert_forward_slash(self._ssl_key),
             'pid_file': _convert_forward_slash(self._pid_file),
             'serverid': self._serverid,
             'lc_messages_dir': _convert_forward_slash(
                 self._lc_messages_dir),
         }
+        options.update(**kwargs)
         try:
             fp = open(self._option_file, 'w')
             fp.write(self._cnf.format(**options))
             fp.close()
+        except Exception as ex:
+            LOGGER.error("Failed to write config file {0}".format(ex))
+            sys.exit(1)
+
+    def start(self, **kwargs):
+        if self.check_running():
+            LOGGER.error("MySQL server '{name}' already running".format(
+                name=self.name))
+            return
+
+        self.update_config(**kwargs)
+        try:
             self._start_server()
             for i in range(10):
                 if self.check_running():
diff --git a/tests/test_abstracts.py b/tests/test_abstracts.py
index ca376e4..662ac22 100644
--- a/tests/test_abstracts.py
+++ b/tests/test_abstracts.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -194,7 +194,13 @@ class ConnectionSubclasses(tests.MySQLConnectorTests):
         exp = {'insert_id': 0, 'affected_rows': 0,
                'field_count': 0, 'warning_count': 0,
                'status_flag': 0}
-        self.assertEqual(exp, self.cnx.cmd_refresh(refresh))
+        result = self.cnx.cmd_refresh(refresh)
+        for key in set(result.keys()) ^ set(exp.keys()):
+            try:
+                del result[key]
+            except KeyError:
+                del exp[key]
+        self.assertEqual(exp, result)
 
         query = "SHOW GLOBAL STATUS LIKE 'Uptime_since_flush_status'"
         pre_flush = int(self.cnx.info_query(query)[1])
diff --git a/tests/test_bugs.py b/tests/test_bugs.py
index 390b1b8..fc26488 100644
--- a/tests/test_bugs.py
+++ b/tests/test_bugs.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -44,6 +44,7 @@ from threading import Thread
 import traceback
 import time
 import unittest
+import pickle
 
 import tests
 from tests import foreach_cnx, cnx_config
@@ -52,6 +53,7 @@ from mysql.connector import (connection, cursor, conversion, protocol,
                              errors, constants, pooling)
 from mysql.connector.optionfiles import read_option_files
 import mysql.connector
+import cpy_distutils
 
 try:
     from mysql.connector.connection_cext import CMySQLConnection
@@ -62,6 +64,8 @@ except ImportError:
 ERR_NO_CEXT = "C Extension not available"
 
 
+@unittest.skipIf(tests.MYSQL_VERSION == (5, 7, 4),
+                 "Bug328998 not tested with MySQL version 5.7.4")
 class Bug328998Tests(tests.MySQLConnectorTests):
     """Tests where connection timeout has been set"""
 
@@ -2381,6 +2385,7 @@ class BugOra16217765(tests.MySQLConnectorTests):
         user = self.users['sha256user']
         config['user'] = user['username']
         config['password'] = user['password']
+        config['auth_plugin'] = user['auth_plugin']
         self.assertRaises(errors.InterfaceError, connection.MySQLConnection,
                           **config)
         if CMySQLConnection:
@@ -4196,3 +4201,200 @@ class BugOra21530841(tests.MySQLConnectorTests):
         cur.execute(query)
         cur.fetchone()
         cur.close()
+
+
+class BugOra25397650(tests.MySQLConnectorTests):
+    """BUG#25397650: CERTIFICATE VALIDITY NOT VERIFIED 
+    """
+    def setUp(self):
+        self.config = tests.get_mysql_config()
+        self.config = tests.get_mysql_config()
+        self.config.update({
+            'ssl_ca': os.path.abspath(
+                os.path.join(tests.SSL_DIR, 'tests_CA_cert.pem')),
+            'ssl_cert': os.path.abspath(
+                os.path.join(tests.SSL_DIR, 'tests_client_cert.pem')),
+            'ssl_key': os.path.abspath(
+                os.path.join(tests.SSL_DIR, 'tests_client_key.pem')),
+        })
+        self.mysql_server = tests.MYSQL_SERVERS[0]
+        self._use_expired_cert()
+
+    def tearDown(self):
+        self._use_original_cert()
+        self._ensure_up()
+
+    def _ensure_up(self):
+        # Start the MySQL server again
+        if not self.mysql_server.check_running():
+            self.mysql_server.start()
+
+            if not self.mysql_server.wait_up():
+                self.fail("Failed restarting MySQL server after test")
+
+    def _use_original_cert(self):
+        self.mysql_server.stop()
+        self.mysql_server.wait_down()
+
+        self.mysql_server.start()
+        self.mysql_server.wait_up()
+        time.sleep(2)
+
+    def _use_expired_cert(self):
+        self.mysql_server.stop()
+        self.mysql_server.wait_down()
+
+        cert = os.path.abspath(
+            os.path.join(tests.SSL_DIR, 'tests_expired_server_cert.pem'))
+        key = os.path.abspath(
+            os.path.join(tests.SSL_DIR, 'tests_expired_server_key.pem'))
+        if os.name == 'nt':
+            cert = os.path.normpath(cert)
+            cert = cert.replace('\\', '\\\\')
+            key = os.path.normpath(key)
+            key = key.replace('\\', '\\\\')
+        self.mysql_server.start(ssl_cert=cert, ssl_key=key)
+        self.mysql_server.wait_up()
+        time.sleep(2)
+
+    def test_pure_verify_server_certifcate(self):
+        self.config["use_pure"] = True
+        self.config['ssl_verify_cert'] = True
+        self.assertRaises(errors.InterfaceError,
+            mysql.connector.connect, **self.config)
+        self.config['ssl_verify_cert'] = False
+        mysql.connector.connect(**self.config)
+
+    def test_cext_verify_server_certifcate(self):
+        self.config["use_pure"] = False
+        self.config['ssl_verify_cert'] = True
+        self.assertRaises(errors.InterfaceError,
+            mysql.connector.connect, **self.config)
+        self.config['ssl_verify_cert'] = False
+        mysql.connector.connect(**self.config)
+
+
+class BugOra25589496(tests.MySQLConnectorTests):
+    """BUG#25589496: COMMITS RELATED TO "BUG22529828" BROKE BINARY DATA
+    HANDLING FOR PYTHON 2.7
+    """
+    def setUp(self):
+        config = tests.get_mysql_config()
+        self.cnx = connection.MySQLConnection(**config)
+        self.tbl = "Bug25589496"
+        self.cnx.cmd_query("DROP TABLE IF EXISTS {0}".format(self.tbl))
+
+    def tearDown(self):
+        self.cnx.cmd_query("DROP TABLE IF EXISTS {0}".format(self.tbl))
+        self.cnx.close()
+
+    def test_insert_binary(self):
+        table = """
+        CREATE TABLE {0} (
+            `id` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
+            `section` VARCHAR(50) NOT NULL,
+            `pickled` LONGBLOB NOT NULL
+        )
+        """.format(self.tbl)
+        cursor = self.cnx.cursor()
+        cursor.execute(table)
+
+        pickled = pickle.dumps({'a': 'b'}, pickle.HIGHEST_PROTOCOL)
+        add_row_q = "INSERT INTO {0} (section, pickled) " \
+                    "VALUES (%(section)s, %(pickled)s)".format(self.tbl)
+
+        new_row = cursor.execute(add_row_q, {'section': 'foo',
+                                             'pickled': pickled})
+        self.cnx.commit()
+        self.assertEqual(1, cursor.lastrowid)
+        cursor.close()
+
+
+class BugOra25383644(tests.MySQLConnectorTests):
+    """BUG#25383644: LOST SERVER CONNECTION LEAKS POOLED CONNECTIONS
+    """
+    def setUp(self):
+        config = tests.get_mysql_config()
+        config["pool_size"] = 3
+        self.cnxpool = pooling.MySQLConnectionPool(**config)
+        self.mysql_server = tests.MYSQL_SERVERS[0]
+
+    def test_pool_exhaustion(self):
+        sql = "SELECT * FROM dummy"
+
+        i = 4
+        while i > 0:
+            cnx = self.cnxpool.get_connection()
+            cur = cnx.cursor()
+            try:
+                self.mysql_server.stop()
+                self.mysql_server.wait_down()
+                cur.execute(sql)
+            except mysql.connector.errors.OperationalError:
+                try:
+                    cur.close()
+                    cnx.close()
+                except mysql.connector.errors.OperationalError:
+                    pass
+            finally:
+                i -= 1
+                if not self.mysql_server.check_running():
+                    self.mysql_server.start()
+                    self.mysql_server.wait_up()
+
+
+class BugOra25558885(tests.MySQLConnectorTests):
+    """BUG#25558885: ERROR 2013 (LOST CONNECTION TO MYSQL SERVER) USING C
+    EXTENSIONS
+    """
+    def setUp(self):
+        pass
+
+    def _long_query(self, config, cursor_class):
+        db_conn = mysql.connector.connect(**config)
+        cur = db_conn.cursor(cursor_class=cursor_class)
+        cur.execute("select sleep(15)")
+        cur.close()
+        db_conn.disconnect()
+
+    def test_cext_cnx(self):
+        config = tests.get_mysql_config()
+        config["use_pure"] = False
+        del config["connection_timeout"]
+        cursor_class = mysql.connector.cursor_cext.CMySQLCursorBufferedRaw
+        self._long_query(config, cursor_class)
+
+    def test_pure_cnx(self):
+        config = tests.get_mysql_config()
+        config["use_pure"] = True
+        del config["connection_timeout"]
+        cursor_class = mysql.connector.cursor.MySQLCursorBufferedRaw
+        self._long_query(config, cursor_class)
+
+
+class BugOra20736339(tests.MySQLConnectorTests):
+    """BUG#20736339: C EXTENSION FAILS TO COMPILE IF MYSQL_CONFIG RETURN MORE
+    THAN ONE INCLUDE DIR
+    """
+    def test_parse_mysql_config(self):
+        options = ['cflags', 'include', 'libs', 'libs_r', 'plugindir', 'version']
+        includes = ["/mysql/include", "/mysql/another_include"]
+        config = """
+        -I/mysql/include -fabi-version=2 -fno-omit-frame-pointer
+        -I{0}
+        -L/mysql/lib -lmysqlclient -lpthread -lm -lrt -lssl -lcrypto -ldl
+        -L/mysql/lib -lmysqlclient -lpthread -lm -lrt -lssl -lcrypto -ldl
+        /mysql/lib/plugin
+        5.7.17
+        """
+
+        info = cpy_distutils.parse_mysql_config_info(options,
+            config.strip().format(includes[0]))
+        self.assertEqual(1, len(info["include"]))
+        self.assertEqual(includes[0], info["include"][0])
+
+        info = cpy_distutils.parse_mysql_config_info(options,
+            config.strip().format(" -I".join(includes)))
+        self.assertEqual(2, len(info["include"]))
+        self.assertEqual(includes[0], info["include"][0])
+        self.assertEqual(includes[1], info["include"][1])
diff --git a/tests/test_django.py b/tests/test_django.py
index 45c2b13..6a94f3b 100644
--- a/tests/test_django.py
+++ b/tests/test_django.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -60,6 +60,7 @@ if DJANGO_AVAILABLE:
             'TEST_COLLATION': 'utf8_general_ci',
             'CONN_MAX_AGE': 0,
             'AUTOCOMMIT': True,
+            'TIME_ZONE': None,
         },
     }
     settings.SECRET_KEY = "django_tests_secret_key"
@@ -92,15 +93,11 @@ FOREIGN KEY (id_t1) REFERENCES django_t1(id) ON DELETE CASCADE
 
 # Have to load django.db to make importing db backend work for Django < 1.6
 import django.db  # pylint: disable=W0611
-if tests.DJANGO_VERSION >= (1, 6):
-    if tests.DJANGO_VERSION >= (1, 8):
-        from django.db.backends.base.introspection import FieldInfo
-    else:
-        from django.db.backends import FieldInfo
 from django.db.backends.signals import connection_created
 from django.utils.safestring import SafeBytes, SafeText
 
 import mysql.connector
+from mysql.connector.django.introspection import FieldInfo
 
 if DJANGO_AVAILABLE:
     from mysql.connector.django.base import (
@@ -147,14 +144,14 @@ class DjangoIntrospection(tests.MySQLConnectorTests):
 
     def test_get_table_list(self):
         cur = self.cnx.cursor()
-        exp = list(TABLES.keys())
-        for exp in list(TABLES.keys()):
+        for exp in TABLES.keys():
             if sys.version_info < (2, 7):
                 self.assertTrue(exp in self.introspect.get_table_list(cur))
             else:
-                self.assertIn(exp, self.introspect.get_table_list(cur),
-                              "Table {table_name} not in table list".format(
-                                  table_name=exp))
+                res = any(table.name == exp
+                          for table in self.introspect.get_table_list(cur))
+                self.assertTrue(res, "Table {table_name} not in table list"
+                                     "".format(table_name=exp))
 
     def test_get_table_description(self):
         cur = self.cnx.cursor()
@@ -165,24 +162,39 @@ class DjangoIntrospection(tests.MySQLConnectorTests):
                 ('c1', 3, None, None, None, None, 1, 16392),
                 ('c2', 253, None, 20, None, None, 1, 16388)
             ]
-        else:
+        elif tests.DJANGO_VERSION < (1, 8):
             exp = [
-                FieldInfo(name='id', type_code=3, display_size=None,
+                FieldInfo(name=u'id', type_code=3, display_size=None,
                           internal_size=None, precision=None, scale=None,
                           null_ok=0),
-                FieldInfo(name='c1', type_code=3, display_size=None,
+                FieldInfo(name=u'c1', type_code=3, display_size=None,
                           internal_size=None, precision=None, scale=None,
                           null_ok=1),
-                FieldInfo(name='c2', type_code=253, display_size=None,
+                FieldInfo(name=u'c2', type_code=253, display_size=None,
                           internal_size=20, precision=None, scale=None,
                           null_ok=1)
             ]
+        else:
+            exp = [
+                FieldInfo(name=u'id', type_code=3, display_size=None,
+                          internal_size=None, precision=10, scale=None,
+                          null_ok=0, extra=u'auto_increment'),
+                FieldInfo(name=u'c1', type_code=3, display_size=None,
+                          internal_size=None, precision=10, scale=None,
+                          null_ok=1, extra=u''),
+                FieldInfo(name=u'c2', type_code=253, display_size=None,
+                          internal_size=20, precision=None, scale=None,
+                          null_ok=1, extra=u'')
+            ]
         res = self.introspect.get_table_description(cur, 'django_t1')
         self.assertEqual(exp, res)
 
     def test_get_relations(self):
         cur = self.cnx.cursor()
-        exp = {1: (0, 'django_t1')}
+        if tests.DJANGO_VERSION < (1, 8):
+            exp = {1: (0, 'django_t1')}
+        else:
+            exp = {u'id_t1': (u'id', u'django_t1')}
         self.assertEqual(exp, self.introspect.get_relations(cur, 'django_t2'))
 
     def test_get_key_columns(self):
@@ -204,6 +216,30 @@ class DjangoIntrospection(tests.MySQLConnectorTests):
         res = self.introspect.get_primary_key_column(cur, 'django_t1')
         self.assertEqual('id', res)
 
+    def test_get_constraints(self):
+        cur = self.cnx.cursor()
+        exp = {
+            'PRIMARY': {'check': False,
+                        'columns': ['id'],
+                        'foreign_key': None,
+                        'index': True,
+                        'primary_key': True,
+                        'unique': True},
+            'django_t2_ibfk_1': {'check': False,
+                                 'columns': ['id_t1'],
+                                 'foreign_key': ('django_t1', 'id'),
+                                 'index': False,
+                                 'primary_key': False,
+                                 'unique': False},
+            'id_t1': {'check': False,
+                      'columns': ['id_t1'],
+                      'foreign_key': None,
+                      'index': True,
+                      'primary_key': False,
+                      'unique': False}
+        }
+        self.assertEqual(
+            exp, self.introspect.get_constraints(cur, 'django_t2'))
 
 @unittest.skipIf(not DJANGO_AVAILABLE, "Django not available")
 class DjangoDatabaseWrapper(tests.MySQLConnectorTests):
@@ -277,26 +313,49 @@ class DjangoDatabaseOperations(tests.MySQLConnectorTests):
         self.dbo = DatabaseOperations(self.cnx)
 
     def test_value_to_db_time(self):
-        self.assertEqual(None, self.dbo.value_to_db_time(None))
+        if tests.DJANGO_VERSION < (1, 9):
+            value_to_db_time = self.dbo.value_to_db_time
+        else:
+            value_to_db_time = self.dbo.adapt_timefield_value
+
+        self.assertEqual(None, value_to_db_time(None))
 
         value = datetime.time(0, 0, 0)
         exp = self.conn.converter._time_to_mysql(value)
-        self.assertEqual(exp, self.dbo.value_to_db_time(value))
+        self.assertEqual(exp, value_to_db_time(value))
 
         value = datetime.time(2, 5, 7)
         exp = self.conn.converter._time_to_mysql(value)
-        self.assertEqual(exp, self.dbo.value_to_db_time(value))
+        self.assertEqual(exp, value_to_db_time(value))
 
     def test_value_to_db_datetime(self):
-        self.assertEqual(None, self.dbo.value_to_db_datetime(None))
+        if tests.DJANGO_VERSION < (1, 9):
+            value_to_db_datetime = self.dbo.value_to_db_datetime
+        else:
+            value_to_db_datetime = self.dbo.adapt_datetimefield_value
+
+        self.assertEqual(None, value_to_db_datetime(None))
 
         value = datetime.datetime(1, 1, 1)
         exp = self.conn.converter._datetime_to_mysql(value)
-        self.assertEqual(exp, self.dbo.value_to_db_datetime(value))
+        self.assertEqual(exp, value_to_db_datetime(value))
 
         value = datetime.datetime(2, 5, 7, 10, 10)
         exp = self.conn.converter._datetime_to_mysql(value)
-        self.assertEqual(exp, self.dbo.value_to_db_datetime(value))
+        self.assertEqual(exp, value_to_db_datetime(value))
+
+    def test_bulk_insert_sql(self):
+        num_values = 5
+        fields = ["col1", "col2", "col3"]
+        placeholder_rows = [["%s"] * len(fields) for _ in range(num_values)]
+        exp = "VALUES {0}".format(", ".join(
+            ["({0})".format(", ".join(["%s"] * len(fields)))] * num_values))
+        if tests.DJANGO_VERSION < (1, 9):
+            self.assertEqual(
+                exp, self.dbo.bulk_insert_sql(fields, num_values))
+        else:
+            self.assertEqual(
+                exp, self.dbo.bulk_insert_sql(fields, placeholder_rows))
 
 
 class DjangoMySQLConverterTests(tests.MySQLConnectorTests):
diff --git a/tests/test_setup.py b/tests/test_setup.py
index 11d0362..74a0313 100644
--- a/tests/test_setup.py
+++ b/tests/test_setup.py
@@ -1,5 +1,5 @@
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -132,7 +132,8 @@ class SetupInfoTests(tests.MySQLConnectorTests):
         for clsfr in setupinfo.classifiers:
             if 'Programming Language :: Python' in clsfr:
                 ver = clsfr.replace('Programming Language :: Python :: ', '')
-                if ver not in ('2.6', '2.7', '3', '3.1', '3.2', '3.3'):
+                if ver not in ('2.6', '2.7', '3', '3.1', '3.2', '3.3', '3.4',
+                               '3.5'):
                     self.fail('Unsupported version in classifiers')
             if 'Development Status ::' in clsfr:
                 status = clsfr.replace('Development Status :: ', '')
diff --git a/unittests.py b/unittests.py
index bb852e0..bfcc19a 100644
--- a/unittests.py
+++ b/unittests.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 # MySQL Connector/Python - MySQL driver written in Python.
-# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
 
 # MySQL Connector/Python is licensed under the terms of the GPLv2
 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -144,17 +144,17 @@ ssl
 # Platform specifics
 if os.name == 'nt':
     MY_CNF += '\n'.join((
-        "ssl-ca = {ssl_dir}\\\\tests_CA_cert.pem",
-        "ssl-cert = {ssl_dir}\\\\tests_server_cert.pem",
-        "ssl-key = {ssl_dir}\\\\tests_server_key.pem",
+        "ssl-ca = {ssl_ca}",
+        "ssl-cert = {ssl_cert}",
+        "ssl-key = {ssl_key}",
     ))
     MYSQL_DEFAULT_BASE = os.path.join(
         "C:/", "Program Files", "MySQL", "MySQL Server 5.6")
 else:
     MY_CNF += '\n'.join((
-        "ssl-ca = {ssl_dir}/tests_CA_cert.pem",
-        "ssl-cert = {ssl_dir}/tests_server_cert.pem",
-        "ssl-key = {ssl_dir}/tests_server_key.pem",
+        "ssl-ca = {ssl_ca}",
+        "ssl-cert = {ssl_cert}",
+        "ssl-key = {ssl_key}",
         "innodb_flush_method = O_DIRECT",
     ))
     MYSQL_DEFAULT_BASE = os.path.join('/', 'usr', 'local', 'mysql')
@@ -603,6 +603,9 @@ def init_mysql_server(port, options):
             port=port,
             unix_socket_folder=options.unix_socket_folder,
             ssl_folder=os.path.abspath(tests.SSL_DIR),
+            ssl_ca="tests_CA_cert.pem",
+            ssl_cert="tests_server_cert.pem",
+            ssl_key="tests_server_key.pem",
             name=name,
             sharedir=options.mysql_sharedir)
     except tests.mysqld.MySQLBootstrapError as err:

--- End Message ---
--- Begin Message ---
Hi,

On Sat, May 27, 2017 at 07:32:45PM -0400, Sandro Tosi wrote:
> 2.1.6 has just been uploaded, apologies for the delay

Thanks. Unblocked.

Cheers,

Ivo

--- End Message ---

Reply to: