diff --git a/connector.go b/connector.go
new file mode 100644
index 000000000..4efb96a34
--- /dev/null
+++ b/connector.go
@@ -0,0 +1,143 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+	"context"
+	"database/sql/driver"
+	"net"
+)
+
+type connector struct {
+	cfg *Config // immutable private copy.
+}
+
+// Connect implements driver.Connector interface.
+// Connect returns a connection to the database.
+func (c *connector) Connect(ctx context.Context) (driver.Conn, error) {
+	var err error
+
+	// New mysqlConn
+	mc := &mysqlConn{
+		maxAllowedPacket: maxPacketSize,
+		maxWriteSize:     maxPacketSize - 1,
+		closech:          make(chan struct{}),
+		cfg:              c.cfg,
+	}
+	mc.parseTime = mc.cfg.ParseTime
+
+	// Connect to Server
+	// TODO: needs RegisterDialContext
+	dialsLock.RLock()
+	dial, ok := dials[mc.cfg.Net]
+	dialsLock.RUnlock()
+	if ok {
+		mc.netConn, err = dial(mc.cfg.Addr)
+	} else {
+		nd := net.Dialer{Timeout: mc.cfg.Timeout}
+		mc.netConn, err = nd.DialContext(ctx, mc.cfg.Net, mc.cfg.Addr)
+	}
+	if err != nil {
+		if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
+			errLog.Print("net.Error from Dial()': ", nerr.Error())
+			return nil, driver.ErrBadConn
+		}
+		return nil, err
+	}
+
+	// Enable TCP Keepalives on TCP connections
+	if tc, ok := mc.netConn.(*net.TCPConn); ok {
+		if err := tc.SetKeepAlive(true); err != nil {
+			// Don't send COM_QUIT before handshake.
+			mc.netConn.Close()
+			mc.netConn = nil
+			return nil, err
+		}
+	}
+
+	// Call startWatcher for context support (From Go 1.8)
+	mc.startWatcher()
+	if err := mc.watchCancel(ctx); err != nil {
+		return nil, err
+	}
+	defer mc.finish()
+
+	mc.buf = newBuffer(mc.netConn)
+
+	// Set I/O timeouts
+	mc.buf.timeout = mc.cfg.ReadTimeout
+	mc.writeTimeout = mc.cfg.WriteTimeout
+
+	// Reading Handshake Initialization Packet
+	authData, plugin, err := mc.readHandshakePacket()
+	if err != nil {
+		mc.cleanup()
+		return nil, err
+	}
+
+	if plugin == "" {
+		plugin = defaultAuthPlugin
+	}
+
+	// Send Client Authentication Packet
+	authResp, err := mc.auth(authData, plugin)
+	if err != nil {
+		// try the default auth plugin, if using the requested plugin failed
+		errLog.Print("could not use requested auth plugin '"+plugin+"': ", err.Error())
+		plugin = defaultAuthPlugin
+		authResp, err = mc.auth(authData, plugin)
+		if err != nil {
+			mc.cleanup()
+			return nil, err
+		}
+	}
+	if err = mc.writeHandshakeResponsePacket(authResp, plugin); err != nil {
+		mc.cleanup()
+		return nil, err
+	}
+
+	// Handle response to auth packet, switch methods if possible
+	if err = mc.handleAuthResult(authData, plugin); err != nil {
+		// Authentication failed and MySQL has already closed the connection
+		// (https://dev.mysql.com/doc/internals/en/authentication-fails.html).
+		// Do not send COM_QUIT, just cleanup and return the error.
+		mc.cleanup()
+		return nil, err
+	}
+
+	if mc.cfg.MaxAllowedPacket > 0 {
+		mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket
+	} else {
+		// Get max allowed packet size
+		maxap, err := mc.getSystemVar("max_allowed_packet")
+		if err != nil {
+			mc.Close()
+			return nil, err
+		}
+		mc.maxAllowedPacket = stringToInt(maxap) - 1
+	}
+	if mc.maxAllowedPacket < maxPacketSize {
+		mc.maxWriteSize = mc.maxAllowedPacket
+	}
+
+	// Handle DSN Params
+	err = mc.handleParams()
+	if err != nil {
+		mc.Close()
+		return nil, err
+	}
+
+	return mc, nil
+}
+
+// Driver implements driver.Connector interface.
+// Driver returns &MySQLDriver{}.
+func (c *connector) Driver() driver.Driver {
+	return &MySQLDriver{}
+}
diff --git a/driver.go b/driver.go
index 9f4967087..48fb82ba7 100644
--- a/driver.go
+++ b/driver.go
@@ -17,6 +17,7 @@
 package mysql
 
 import (
+	"context"
 	"database/sql"
 	"database/sql/driver"
 	"net"
@@ -52,116 +53,14 @@ func RegisterDial(net string, dial DialFunc) {
 // See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how
 // the DSN string is formatted
 func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
-	var err error
-
-	// New mysqlConn
-	mc := &mysqlConn{
-		maxAllowedPacket: maxPacketSize,
-		maxWriteSize:     maxPacketSize - 1,
-		closech:          make(chan struct{}),
-	}
-	mc.cfg, err = ParseDSN(dsn)
-	if err != nil {
-		return nil, err
-	}
-	mc.parseTime = mc.cfg.ParseTime
-
-	// Connect to Server
-	dialsLock.RLock()
-	dial, ok := dials[mc.cfg.Net]
-	dialsLock.RUnlock()
-	if ok {
-		mc.netConn, err = dial(mc.cfg.Addr)
-	} else {
-		nd := net.Dialer{Timeout: mc.cfg.Timeout}
-		mc.netConn, err = nd.Dial(mc.cfg.Net, mc.cfg.Addr)
-	}
-	if err != nil {
-		if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
-			errLog.Print("net.Error from Dial()': ", nerr.Error())
-			return nil, driver.ErrBadConn
-		}
-		return nil, err
-	}
-
-	// Enable TCP Keepalives on TCP connections
-	if tc, ok := mc.netConn.(*net.TCPConn); ok {
-		if err := tc.SetKeepAlive(true); err != nil {
-			// Don't send COM_QUIT before handshake.
-			mc.netConn.Close()
-			mc.netConn = nil
-			return nil, err
-		}
-	}
-
-	// Call startWatcher for context support (From Go 1.8)
-	mc.startWatcher()
-
-	mc.buf = newBuffer(mc.netConn)
-
-	// Set I/O timeouts
-	mc.buf.timeout = mc.cfg.ReadTimeout
-	mc.writeTimeout = mc.cfg.WriteTimeout
-
-	// Reading Handshake Initialization Packet
-	authData, plugin, err := mc.readHandshakePacket()
+	cfg, err := ParseDSN(dsn)
 	if err != nil {
-		mc.cleanup()
 		return nil, err
 	}
-	if plugin == "" {
-		plugin = defaultAuthPlugin
+	c := &connector{
+		cfg: cfg,
 	}
-
-	// Send Client Authentication Packet
-	authResp, err := mc.auth(authData, plugin)
-	if err != nil {
-		// try the default auth plugin, if using the requested plugin failed
-		errLog.Print("could not use requested auth plugin '"+plugin+"': ", err.Error())
-		plugin = defaultAuthPlugin
-		authResp, err = mc.auth(authData, plugin)
-		if err != nil {
-			mc.cleanup()
-			return nil, err
-		}
-	}
-	if err = mc.writeHandshakeResponsePacket(authResp, plugin); err != nil {
-		mc.cleanup()
-		return nil, err
-	}
-
-	// Handle response to auth packet, switch methods if possible
-	if err = mc.handleAuthResult(authData, plugin); err != nil {
-		// Authentication failed and MySQL has already closed the connection
-		// (https://dev.mysql.com/doc/internals/en/authentication-fails.html).
-		// Do not send COM_QUIT, just cleanup and return the error.
-		mc.cleanup()
-		return nil, err
-	}
-
-	if mc.cfg.MaxAllowedPacket > 0 {
-		mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket
-	} else {
-		// Get max allowed packet size
-		maxap, err := mc.getSystemVar("max_allowed_packet")
-		if err != nil {
-			mc.Close()
-			return nil, err
-		}
-		mc.maxAllowedPacket = stringToInt(maxap) - 1
-	}
-	if mc.maxAllowedPacket < maxPacketSize {
-		mc.maxWriteSize = mc.maxAllowedPacket
-	}
-
-	// Handle DSN Params
-	err = mc.handleParams()
-	if err != nil {
-		mc.Close()
-		return nil, err
-	}
-
-	return mc, nil
+	return c.Connect(context.Background())
 }
 
 func init() {
diff --git a/driver_go1.10.go b/driver_go1.10.go
new file mode 100644
index 000000000..b0ee134bd
--- /dev/null
+++ b/driver_go1.10.go
@@ -0,0 +1,45 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// +build go1.10
+
+package mysql
+
+import (
+	"crypto/rsa"
+	"database/sql/driver"
+	"math/big"
+)
+
+// NewConnector returns new driver.Connector.
+func NewConnector(cfg *Config) driver.Connector {
+	copyCfg := *cfg
+	copyCfg.tls = cfg.tls.Clone()
+	copyCfg.Params = make(map[string]string, len(cfg.Params))
+	for k, v := range cfg.Params {
+		copyCfg.Params[k] = v
+	}
+	if cfg.pubKey != nil {
+		copyCfg.pubKey = &rsa.PublicKey{
+			N: new(big.Int).Set(cfg.pubKey.N),
+			E: cfg.pubKey.E,
+		}
+	}
+	return &connector{cfg: &copyCfg}
+}
+
+// OpenConnector implements driver.DriverContext.
+func (d MySQLDriver) OpenConnector(dsn string) (driver.Connector, error) {
+	cfg, err := ParseDSN(dsn)
+	if err != nil {
+		return nil, err
+	}
+	return &connector{
+		cfg: cfg,
+	}, nil
+}
diff --git a/driver_go1.10_test.go b/driver_go1.10_test.go
new file mode 100644
index 000000000..a9d784c52
--- /dev/null
+++ b/driver_go1.10_test.go
@@ -0,0 +1,17 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2018 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// +build go1.10
+
+package mysql
+
+import (
+	"database/sql/driver"
+)
+
+var _ driver.DriverContext = &MySQLDriver{}