diff --git a/.travis.yml b/.travis.yml
index 1aa25416..10411637 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,13 +1,24 @@
+# Travis CI configuration file for psycopg2
+
+dist: trusty
+sudo: required
 language: python
 
 python:
-  - 2.6
   - 2.7
-
-before_script:
-  - psql -c 'create database psycopg2_test;' -U postgres
+  - 3.6-dev
+  - 2.6
+  - 3.5
+  - 3.4
+  - 3.3
+  - 3.2
 
 install:
   - python setup.py install
+  - sudo scripts/travis_prepare.sh
 
-script: make check
+script:
+  - scripts/travis_test.sh
+
+notifications:
+  email: false
diff --git a/README.rst b/README.rst
index 51d2d6b6..f18be564 100644
--- a/README.rst
+++ b/README.rst
@@ -44,3 +44,8 @@ For any other resource (source code repository, bug tracker, mailing list)
 please check the `project homepage`__.
 
 .. __: http://initd.org/psycopg/
+
+
+.. image:: https://travis-ci.org/psycopg/psycopg2.svg?branch=master
+    :target: https://travis-ci.org/psycopg/psycopg2
+    :alt: Build Status
diff --git a/scripts/travis_prepare.sh b/scripts/travis_prepare.sh
new file mode 100755
index 00000000..f4e86118
--- /dev/null
+++ b/scripts/travis_prepare.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+set -e
+
+# Prepare the test databases in Travis CI.
+# The script should be run with sudo.
+# The script is not idempotent: it assumes the machine in a clean state
+# and is designed for a sudo-enabled Trusty environment.
+
+set_param () {
+    # Set a parameter in a postgresql.conf file
+    version=$1
+    param=$2
+    value=$3
+
+    sed -i "s/^\s*#\?\s*$param.*/$param = $value/" \
+        "/etc/postgresql/$version/psycopg/postgresql.conf"
+}
+
+create () {
+    version=$1
+    port=$2
+    dbname=psycopg2_test
+
+    pg_createcluster -p $port --start-conf manual $version psycopg
+    set_param "$version" max_prepared_transactions 10
+    pg_ctlcluster "$version" psycopg start
+
+    sudo -u postgres psql -c "create user travis" "port=$port"
+    sudo -u postgres psql -c "create database $dbname" "port=$port"
+    sudo -u postgres psql -c "grant create on database $dbname to travis" "port=$port"
+    sudo -u postgres psql -c "create extension hstore" "port=$port dbname=$dbname"
+}
+
+
+# Would give a permission denied error in the travis build dir
+cd /
+
+create 9.6 54396
+create 9.5 54395
+create 9.4 54394
+create 9.3 54393
+create 9.2 54392
diff --git a/scripts/travis_test.sh b/scripts/travis_test.sh
new file mode 100755
index 00000000..df9413a1
--- /dev/null
+++ b/scripts/travis_test.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Run the tests in all the databases
+# The script is designed for a Trusty environment.
+
+set -e
+
+run_test () {
+    version=$1
+    port=$2
+    dbname=psycopg2_test
+
+    printf "\n\nRunning tests against PostgreSQL $version\n\n"
+    export PSYCOPG2_TESTDB=$dbname
+    export PSYCOPG2_TESTDB_PORT=$port
+    export PSYCOPG2_TESTDB_USER=travis
+    make check
+
+    printf "\n\nRunning tests against PostgreSQL $version (green mode)\n\n"
+    export PSYCOPG2_TEST_GREEN=1
+    make check
+}
+
+run_test 9.6 54396
+run_test 9.5 54395
+run_test 9.4 54394
+run_test 9.3 54393
+run_test 9.2 54392
diff --git a/tests/test_connection.py b/tests/test_connection.py
index 8744488d..833751b9 100755
--- a/tests/test_connection.py
+++ b/tests/test_connection.py
@@ -465,7 +465,7 @@ class MakeDsnTestCase(ConnectingTestCase):
         conn = self.connect()
         d = conn.get_dsn_parameters()
         self.assertEqual(d['dbname'], dbname)  # the only param we can check reliably
-        self.assertNotIn('password', d)
+        self.assert_('password' not in d, d)
 
 
 class IsolationLevelsTestCase(ConnectingTestCase):
diff --git a/tests/test_module.py b/tests/test_module.py
index 1a9a19d4..6a1606d6 100755
--- a/tests/test_module.py
+++ b/tests/test_module.py
@@ -119,8 +119,8 @@ class ConnectTestCase(unittest.TestCase):
     def test_int_port_param(self):
         psycopg2.connect(database='sony', port=6543)
         dsn = " %s " % self.args[0]
-        self.assertIn(" dbname=sony ", dsn)
-        self.assertIn(" port=6543 ", dsn)
+        self.assert_(" dbname=sony " in dsn, dsn)
+        self.assert_(" port=6543 " in dsn, dsn)
 
     def test_empty_param(self):
         psycopg2.connect(database='sony', password='')
diff --git a/tests/test_quote.py b/tests/test_quote.py
index f74fd854..72c9c1e4 100755
--- a/tests/test_quote.py
+++ b/tests/test_quote.py
@@ -65,11 +65,13 @@ class QuotingTestCase(ConnectingTestCase):
         curs = self.conn.cursor()
         data = 'abcd\x01\x00cdefg'
 
-        with self.assertRaises(ValueError) as e:
+        try:
             curs.execute("SELECT %s", (data,))
-
-        self.assertEquals(str(e.exception),
-            'A string literal cannot contain NUL (0x00) characters.')
+        except ValueError as e:
+            self.assertEquals(str(e),
+                'A string literal cannot contain NUL (0x00) characters.')
+        else:
+            self.fail("ValueError not raised")
 
     def test_binary(self):
         data = b"""some data with \000\013 binary
diff --git a/tests/test_replication.py b/tests/test_replication.py
index ca99038a..2ccd4c77 100644
--- a/tests/test_replication.py
+++ b/tests/test_replication.py
@@ -35,11 +35,7 @@ from testutils import ConnectingTestCase
 
 class ReplicationTestCase(ConnectingTestCase):
     def setUp(self):
-        if not testconfig.repl_dsn:
-            self.skipTest("replication tests disabled by default")
-
         super(ReplicationTestCase, self).setUp()
-
         self.slot = testconfig.repl_slot
         self._slots = []
 
diff --git a/tests/testutils.py b/tests/testutils.py
index d0a34bcf..1dd0c999 100644
--- a/tests/testutils.py
+++ b/tests/testutils.py
@@ -122,6 +122,9 @@ class ConnectingTestCase(unittest.TestCase):
         Should raise a skip test if not available, but guard for None on
         old Python versions.
         """
+        if repl_dsn is None:
+            return self.skipTest("replication tests disabled by default")
+
         if 'dsn' not in kwargs:
             kwargs['dsn'] = repl_dsn
         import psycopg2