internal/atomic: move to separate package
diff --git a/connection.go b/connection.go
index 948a595..6f5c700 100644
--- a/connection.go
+++ b/connection.go
@@ -9,6 +9,8 @@
 package mysql
 
 import (
+	"github.com/go-sql-driver/mysql/internal/atomic"
+
 	"database/sql/driver"
 	"io"
 	"net"
@@ -47,8 +49,8 @@
 	watcher  chan<- mysqlContext
 	closech  chan struct{}
 	finished chan<- struct{}
-	canceled atomicError // set non-nil if conn is canceled
-	closed   atomicBool  // set when conn is closed, before closech is closed
+	canceled atomic.Error // set non-nil if conn is canceled
+	closed   atomic.Bool  // set when conn is closed, before closech is closed
 }
 
 // Handles parameters set in DSN after the connection is established
diff --git a/internal/atomic/atomic.go b/internal/atomic/atomic.go
new file mode 100644
index 0000000..a794491
--- /dev/null
+++ b/internal/atomic/atomic.go
@@ -0,0 +1,73 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2017 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 atomic
+
+import (
+	"sync/atomic"
+)
+
+// noCopy may be embedded into structs which must not be copied
+// after the first use.
+//
+// See https://github.com/golang/go/issues/8005#issuecomment-190753527
+// for details.
+type noCopy struct{}
+
+// Lock is a no-op used by -copylocks checker from `go vet`.
+func (*noCopy) Lock() {}
+
+// Bool is a wrapper around uint32 for usage as a boolean value with
+// atomic access.
+type Bool struct {
+	_noCopy noCopy
+	value   uint32
+}
+
+// IsSet returns wether the current boolean value is true
+func (b *Bool) IsSet() bool {
+	return atomic.LoadUint32(&b.value) > 0
+}
+
+// Set sets the value of the bool regardless of the previous value
+func (b *Bool) Set(value bool) {
+	if value {
+		atomic.StoreUint32(&b.value, 1)
+	} else {
+		atomic.StoreUint32(&b.value, 0)
+	}
+}
+
+// TrySet sets the value of the bool and returns wether the value changed
+func (b *Bool) TrySet(value bool) bool {
+	if value {
+		return atomic.SwapUint32(&b.value, 1) == 0
+	}
+	return atomic.SwapUint32(&b.value, 0) > 0
+}
+
+// Error is a wrapper for atomically accessed error values
+type Error struct {
+	_noCopy noCopy
+	value   atomic.Value
+}
+
+// Set sets the error value regardless of the previous value.
+// The value must not be nil
+func (e *Error) Set(value error) {
+	e.value.Store(value)
+}
+
+// Value returns the current error value
+func (e *Error) Value() error {
+	if v := e.value.Load(); v != nil {
+		// this will panic if the value doesn't implement the error interface
+		return v.(error)
+	}
+	return nil
+}
diff --git a/internal/atomic/atomic_test.go b/internal/atomic/atomic_test.go
new file mode 100644
index 0000000..f22dbb3
--- /dev/null
+++ b/internal/atomic/atomic_test.go
@@ -0,0 +1,99 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2017 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 atomic
+
+import (
+	"errors"
+	"testing"
+)
+
+var (
+	errOne = errors.New("one")
+	errTwo = errors.New("two")
+)
+
+func TestAtomicBool(t *testing.T) {
+	var b Bool
+	if b.IsSet() {
+		t.Fatal("Expected value to be false")
+	}
+
+	b.Set(true)
+	if b.value != 1 {
+		t.Fatal("Set(true) did not set value to 1")
+	}
+	if !b.IsSet() {
+		t.Fatal("Expected value to be true")
+	}
+
+	b.Set(true)
+	if !b.IsSet() {
+		t.Fatal("Expected value to be true")
+	}
+
+	b.Set(false)
+	if b.value != 0 {
+		t.Fatal("Set(false) did not set value to 0")
+	}
+	if b.IsSet() {
+		t.Fatal("Expected value to be false")
+	}
+
+	b.Set(false)
+	if b.IsSet() {
+		t.Fatal("Expected value to be false")
+	}
+	if b.TrySet(false) {
+		t.Fatal("Expected TrySet(false) to fail")
+	}
+	if !b.TrySet(true) {
+		t.Fatal("Expected TrySet(true) to succeed")
+	}
+	if !b.IsSet() {
+		t.Fatal("Expected value to be true")
+	}
+
+	b.Set(true)
+	if !b.IsSet() {
+		t.Fatal("Expected value to be true")
+	}
+	if b.TrySet(true) {
+		t.Fatal("Expected TrySet(true) to fail")
+	}
+	if !b.TrySet(false) {
+		t.Fatal("Expected TrySet(false) to succeed")
+	}
+	if b.IsSet() {
+		t.Fatal("Expected value to be false")
+	}
+
+	b._noCopy.Lock() // we've "tested" it ¯\_(ツ)_/¯
+}
+
+func TestAtomicError(t *testing.T) {
+	var e Error
+	if e.Value() != nil {
+		t.Fatal("Expected value to be nil")
+	}
+
+	e.Set(errOne)
+	if v := e.Value(); v != errOne {
+		if v == nil {
+			t.Fatal("Value is still nil")
+		}
+		t.Fatal("Error did not match")
+	}
+	e.Set(errTwo)
+	if e.Value() == errOne {
+		t.Fatal("Error still matches old error")
+	}
+	if v := e.Value(); v != errTwo {
+		t.Fatal("Error did not match")
+	}
+}
diff --git a/utils.go b/utils.go
index 82da830..0c3729d 100644
--- a/utils.go
+++ b/utils.go
@@ -17,7 +17,6 @@
 	"io"
 	"strings"
 	"sync"
-	"sync/atomic"
 	"time"
 )
 
@@ -756,67 +755,3 @@
 
 	return buf[:pos]
 }
-
-/******************************************************************************
-*                               Sync utils                                    *
-******************************************************************************/
-
-// noCopy may be embedded into structs which must not be copied
-// after the first use.
-//
-// See https://github.com/golang/go/issues/8005#issuecomment-190753527
-// for details.
-type noCopy struct{}
-
-// Lock is a no-op used by -copylocks checker from `go vet`.
-func (*noCopy) Lock() {}
-
-// atomicBool is a wrapper around uint32 for usage as a boolean value with
-// atomic access.
-type atomicBool struct {
-	_noCopy noCopy
-	value   uint32
-}
-
-// IsSet returns wether the current boolean value is true
-func (ab *atomicBool) IsSet() bool {
-	return atomic.LoadUint32(&ab.value) > 0
-}
-
-// Set sets the value of the bool regardless of the previous value
-func (ab *atomicBool) Set(value bool) {
-	if value {
-		atomic.StoreUint32(&ab.value, 1)
-	} else {
-		atomic.StoreUint32(&ab.value, 0)
-	}
-}
-
-// TrySet sets the value of the bool and returns wether the value changed
-func (ab *atomicBool) TrySet(value bool) bool {
-	if value {
-		return atomic.SwapUint32(&ab.value, 1) == 0
-	}
-	return atomic.SwapUint32(&ab.value, 0) > 0
-}
-
-// atomicBool is a wrapper for atomically accessed error values
-type atomicError struct {
-	_noCopy noCopy
-	value   atomic.Value
-}
-
-// Set sets the error value regardless of the previous value.
-// The value must not be nil
-func (ae *atomicError) Set(value error) {
-	ae.value.Store(value)
-}
-
-// Value returns the current error value
-func (ae *atomicError) Value() error {
-	if v := ae.value.Load(); v != nil {
-		// this will panic if the value doesn't implement the error interface
-		return v.(error)
-	}
-	return nil
-}
diff --git a/utils_test.go b/utils_test.go
index 0041892..0d6c668 100644
--- a/utils_test.go
+++ b/utils_test.go
@@ -195,83 +195,3 @@
 	expect("foo''bar", "foo'bar")      // affected
 	expect("foo\"bar", "foo\"bar")     // not affected
 }
-
-func TestAtomicBool(t *testing.T) {
-	var ab atomicBool
-	if ab.IsSet() {
-		t.Fatal("Expected value to be false")
-	}
-
-	ab.Set(true)
-	if ab.value != 1 {
-		t.Fatal("Set(true) did not set value to 1")
-	}
-	if !ab.IsSet() {
-		t.Fatal("Expected value to be true")
-	}
-
-	ab.Set(true)
-	if !ab.IsSet() {
-		t.Fatal("Expected value to be true")
-	}
-
-	ab.Set(false)
-	if ab.value != 0 {
-		t.Fatal("Set(false) did not set value to 0")
-	}
-	if ab.IsSet() {
-		t.Fatal("Expected value to be false")
-	}
-
-	ab.Set(false)
-	if ab.IsSet() {
-		t.Fatal("Expected value to be false")
-	}
-	if ab.TrySet(false) {
-		t.Fatal("Expected TrySet(false) to fail")
-	}
-	if !ab.TrySet(true) {
-		t.Fatal("Expected TrySet(true) to succeed")
-	}
-	if !ab.IsSet() {
-		t.Fatal("Expected value to be true")
-	}
-
-	ab.Set(true)
-	if !ab.IsSet() {
-		t.Fatal("Expected value to be true")
-	}
-	if ab.TrySet(true) {
-		t.Fatal("Expected TrySet(true) to fail")
-	}
-	if !ab.TrySet(false) {
-		t.Fatal("Expected TrySet(false) to succeed")
-	}
-	if ab.IsSet() {
-		t.Fatal("Expected value to be false")
-	}
-
-	ab._noCopy.Lock() // we've "tested" it ¯\_(ツ)_/¯
-}
-
-func TestAtomicError(t *testing.T) {
-	var ae atomicError
-	if ae.Value() != nil {
-		t.Fatal("Expected value to be nil")
-	}
-
-	ae.Set(ErrMalformPkt)
-	if v := ae.Value(); v != ErrMalformPkt {
-		if v == nil {
-			t.Fatal("Value is still nil")
-		}
-		t.Fatal("Error did not match")
-	}
-	ae.Set(ErrPktSync)
-	if ae.Value() == ErrMalformPkt {
-		t.Fatal("Error still matches old error")
-	}
-	if v := ae.Value(); v != ErrPktSync {
-		t.Fatal("Error did not match")
-	}
-}