diff --git a/docs/changelog.txt b/docs/changelog.txt
index 8e12639d8f7e80eac5b2dc8e69ad5835f82c7c54..4eb3fa05f8439a8a134c277d023433d38711ce45 100644
--- a/docs/changelog.txt
+++ b/docs/changelog.txt
@@ -20,8 +20,12 @@ The standard library version!
   methods (other than equality and inequality) now return `NotImplemented`
 * Propagate traceback info to support subclassing of `_patch` by other
   libraries
+* BUGFIX: passing multiple spec arguments to patchers (`spec` , `spec_set` and
+  `autospec`) had unpredictable results, now it is an error
 * BUGFIX: using `spec=True` *and* `create=True` as arguments to patchers could
   result in using `DEFAULT` as the spec. Now it is an error instead
+* BUGFIX: using `spec` or `autospec` arguments to patchers, along with
+  `spec_set=True` did not work correctly
 
 
 2012/02/13 Version 0.8.0
diff --git a/docs/patch.txt b/docs/patch.txt
index 190fa13a6150837c70cd32aef482d620865fd155..d27dbc54167861ecb95ad0c823fb0e4af477dea4 100644
--- a/docs/patch.txt
+++ b/docs/patch.txt
@@ -40,7 +40,7 @@ patch
     `patch` is straightforward to use. The key is to do the patching in the
     right namespace. See the section `where to patch`_.
 
-.. function:: patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=False, new_callable=None, **kwargs)
+.. function:: patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)
 
     `patch` acts as a function decorator, class decorator or a context
     manager. Inside the body of the function or with statement, the `target`
@@ -208,7 +208,7 @@ into a `patch` call using `**`:
 patch.object
 ============
 
-.. function:: patch.object(target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=False, new_callable=None, **kwargs)
+.. function:: patch.object(target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)
 
     patch the named member (`attribute`) on an object (`target`) with a mock
     object.
@@ -336,7 +336,7 @@ magic methods `__getitem__`, `__setitem__`, `__delitem__` and either
 patch.multiple
 ==============
 
-.. function:: patch.multiple(target, spec=None, create=False, spec_set=None, autospec=False, new_callable=None, **kwargs)
+.. function:: patch.multiple(target, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)
 
     Perform multiple patches in a single call. It takes the object to be
     patched (either as an object or a string to fetch the object by importing)
diff --git a/mock.py b/mock.py
index 75aaf736f2c57ad14437353cf6b47172afddfabc..e852bcfeafeb4ac14355fdea291c664e41150eae 100644
--- a/mock.py
+++ b/mock.py
@@ -1089,7 +1089,7 @@ class _patch(object):
                 raise ValueError(
                     "Cannot use 'new' and 'new_callable' together"
                 )
-            if autospec is not False:
+            if autospec is not None:
                 raise ValueError(
                     "Cannot use 'autospec' and 'new_callable' together"
                 )
@@ -1218,17 +1218,38 @@ class _patch(object):
         new_callable = self.new_callable
         self.target = self.getter()
 
+        # normalise False to None
+        if spec is False:
+            spec = None
+        if spec_set is False:
+            spec_set = None
+        if autospec is False:
+            autospec = None
+
+        if spec is not None and autospec is not None:
+            raise TypeError("Can't specify spec and autospec")
+        if ((spec is not None or autospec is not None) and
+            spec_set not in (True, None)):
+            raise TypeError("Can't provide explicit spec_set *and* spec or autospec")
+
         original, local = self.get_original()
 
-        if new is DEFAULT and autospec is False:
+        if new is DEFAULT and autospec is None:
             inherit = False
-            if spec_set == True:
-                spec_set = original
-            elif spec == True:
+            if spec is True:
                 # set spec to the object we are replacing
                 spec = original
+                if spec_set is True:
+                    spec_set = original
+                    spec = None
+            elif spec is not None:
+                if spec_set is True:
+                    spec_set = spec
+                    spec = None
+            elif spec_set is True:
+                spec_set = original
 
-            if (spec or spec_set) is not None:
+            if spec is not None or spec_set is not None:
                 if original is DEFAULT:
                     raise TypeError("Can't use 'spec' with create=True")
                 if isinstance(original, ClassTypes):
@@ -1259,14 +1280,17 @@ class _patch(object):
             if inherit and _is_instance_mock(new):
                 # we can only tell if the instance should be callable if the
                 # spec is not a list
-                if (not _is_list(spec or spec_set) and not
-                    _instance_callable(spec or spec_set)):
+                this_spec = spec
+                if spec_set is not None:
+                    this_spec = spec_set
+                if (not _is_list(this_spec) and not
+                    _instance_callable(this_spec)):
                     Klass = NonCallableMagicMock
 
                 _kwargs.pop('name')
                 new.return_value = Klass(_new_parent=new, _new_name='()',
                                          **_kwargs)
-        elif autospec is not False:
+        elif autospec is not None:
             # spec is ignored, new *must* be default, spec_set is treated
             # as a boolean. Should we check spec is not None and that spec_set
             # is a bool?
@@ -1343,13 +1367,12 @@ def _get_target(target):
 
 def _patch_object(
         target, attribute, new=DEFAULT, spec=None,
-        create=False, spec_set=None, autospec=False,
+        create=False, spec_set=None, autospec=None,
         new_callable=None, **kwargs
     ):
     """
     patch.object(target, attribute, new=DEFAULT, spec=None, create=False,
-                 spec_set=None, autospec=False,
-                 new_callable=None, **kwargs)
+                 spec_set=None, autospec=None, new_callable=None, **kwargs)
 
     patch the named member (`attribute`) on an object (`target`) with a mock
     object.
@@ -1370,9 +1393,8 @@ def _patch_object(
     )
 
 
-def _patch_multiple(target, spec=None, create=False,
-        spec_set=None, autospec=False,
-        new_callable=None, **kwargs
+def _patch_multiple(target, spec=None, create=False, spec_set=None,
+                    autospec=None, new_callable=None, **kwargs
     ):
     """Perform multiple patches in a single call. It takes the object to be
     patched (either as an object or a string to fetch the object by importing)
@@ -1423,8 +1445,7 @@ def _patch_multiple(target, spec=None, create=False,
 
 def patch(
         target, new=DEFAULT, spec=None, create=False,
-        spec_set=None, autospec=False,
-        new_callable=None, **kwargs
+        spec_set=None, autospec=None, new_callable=None, **kwargs
     ):
     """
     `patch` acts as a function decorator, class decorator or a context
diff --git a/tests/testpatch.py b/tests/testpatch.py
index d6ebec3aa1d8712c41a932a1fc23de8fcd9b0732..5f6a1b1cdff66d125196749fd4e89d0d5bc4697b 100644
--- a/tests/testpatch.py
+++ b/tests/testpatch.py
@@ -20,6 +20,7 @@ if inPy3k:
     unicode = str
 
 PTModule = sys.modules[__name__]
+MODNAME = '%s.PTModule' % __name__
 
 
 def _get_proxy(obj, get_only=True):
@@ -687,13 +688,13 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_patch_spec_set(self):
-        @patch('%s.SomeClass' % __name__, spec=SomeClass, spec_set=True)
+        @patch('%s.SomeClass' % __name__, spec_set=SomeClass)
         def test(MockClass):
             MockClass.z = 'foo'
 
         self.assertRaises(AttributeError, test)
 
-        @patch.object(support, 'SomeClass', spec=SomeClass, spec_set=True)
+        @patch.object(support, 'SomeClass', spec_set=SomeClass)
         def test(MockClass):
             MockClass.z = 'foo'
 
@@ -1653,7 +1654,6 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_patch_propogrates_exc_on_exit(self):
-
         class holder:
             exc_info = None, None, None
 
@@ -1666,8 +1666,8 @@ class PatchTest(unittest2.TestCase):
         def with_custom_patch(target):
             getter, attribute = _get_target(target)
             return custom_patch(
-                getter, attribute, DEFAULT, None, False, False,
-                False, None, {}
+                getter, attribute, DEFAULT, None, False, None,
+                None, None, {}
             )
 
         @with_custom_patch('squizz.squozz')
@@ -1690,7 +1690,7 @@ class PatchTest(unittest2.TestCase):
             self.assertRaises(NameError, lambda: doesnotexist)
 
             # check that spec with create is innocuous if the original exists
-            p = patch('%s.PTModule' % __name__, create=True,
+            p = patch(MODNAME, create=True,
                       **{kwarg: True})
             try:
                 p.start()
@@ -1698,5 +1698,56 @@ class PatchTest(unittest2.TestCase):
                 p.stop()
 
 
+    def test_multiple_specs(self):
+        original = PTModule
+        for kwarg in ('spec', 'spec_set'):
+            p = patch(MODNAME, autospec=0, **{kwarg: 0})
+            self.assertRaises(TypeError, p.start)
+            self.assertIs(PTModule, original)
+
+        for kwarg in ('spec', 'autospec'):
+            p = patch(MODNAME, spec_set=0, **{kwarg: 0})
+            self.assertRaises(TypeError, p.start)
+            self.assertIs(PTModule, original)
+
+        for kwarg in ('spec_set', 'autospec'):
+            p = patch(MODNAME, spec=0, **{kwarg: 0})
+            self.assertRaises(TypeError, p.start)
+            self.assertIs(PTModule, original)
+
+
+    def test_specs_false_instead_of_none(self):
+        p = patch(MODNAME, spec=False, spec_set=False, autospec=False)
+        mock = p.start()
+        try:
+            # no spec should have been set, so attribute access should not fail
+            mock.does_not_exist
+            mock.does_not_exist = 3
+        finally:
+            p.stop()
+
+
+    def test_falsey_spec(self):
+        for kwarg in ('spec', 'autospec', 'spec_set'):
+            p = patch(MODNAME, **{kwarg: 0})
+            m = p.start()
+            try:
+                self.assertRaises(AttributeError, getattr, m, 'doesnotexit')
+            finally:
+                p.stop()
+
+
+    def test_spec_set_true(self):
+        for kwarg in ('spec', 'autospec'):
+            p = patch(MODNAME, spec_set=True, **{kwarg: True})
+            m = p.start()
+            try:
+                self.assertRaises(AttributeError, setattr, m,
+                                  'doesnotexist', 'something')
+                self.assertRaises(AttributeError, getattr, m, 'doesnotexist')
+            finally:
+                p.stop()
+
+
 if __name__ == '__main__':
     unittest2.main()