diff --git a/.travis.yml b/.travis.yml
index 8600e8fe327a60497157104c36139359f1faf0a0..dbc744e9f63495a3f722709d742c9ae52e688a7d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -42,6 +42,24 @@ matrix:
         - rustup target add wasm32-unknown-unknown
         - cargo build --target=wasm32-unknown-unknown
 
+    # Sanitizers
+    - rust: nightly
+      os: linux
+      script:
+        - |
+          set -e
+
+          export RUST_TEST_THREADS=1
+          export ASAN_OPTIONS="detect_odr_violation=0 detect_leaks=0"
+          export TSAN_OPTIONS="suppressions=`pwd`/ci/tsan"
+
+          # Run address sanitizer
+          RUSTFLAGS="-Z sanitizer=address" \
+          cargo test --tests --target x86_64-unknown-linux-gnu
+
+          # Run thread sanitizer
+          RUSTFLAGS="-Z sanitizer=thread" \
+          cargo test --tests --target x86_64-unknown-linux-gnu
 
 before_install: set -e
 
diff --git a/ci/tsan b/ci/tsan
new file mode 100644
index 0000000000000000000000000000000000000000..34f76abaf47208dfc531c70e81b5e75a6b68bc1c
--- /dev/null
+++ b/ci/tsan
@@ -0,0 +1,17 @@
+# TSAN suppressions file for `bytes`
+
+# TSAN does not understand fences and `Arc::drop` is implemented using a fence.
+# This causes many false positives.
+race:Arc*drop
+race:arc*Weak*drop
+
+# `std` mpsc is not used in any Bytes code base. This race is triggered by some
+# rust runtime logic.
+race:std*mpsc_queue
+
+# Probably more fences in std.
+race:__call_tls_dtors
+
+# `is_inline` is explicitly called concurrently without synchronization. The
+# safety explanation can be found in a comment.
+race:Inner::is_inline