diff --git a/swift/common/middleware/s3api/controllers/multi_delete.py b/swift/common/middleware/s3api/controllers/multi_delete.py
index 04a6ed37f2..085cdf3e52 100644
--- a/swift/common/middleware/s3api/controllers/multi_delete.py
+++ b/swift/common/middleware/s3api/controllers/multi_delete.py
@@ -14,6 +14,7 @@
 # limitations under the License.
 
 import copy
+import json
 
 from swift.common.constraints import MAX_OBJECT_NAME_LENGTH
 from swift.common.utils import public, StreamingPile
@@ -115,7 +116,30 @@ class MultiObjectDeleteController(Controller):
 
             try:
                 query = req.gen_multipart_manifest_delete_query(self.app)
-                req.get_response(self.app, method='DELETE', query=query)
+                resp = req.get_response(self.app, method='DELETE', query=query,
+                                        headers={'Accept': 'application/json'})
+                # Have to read the response to actually do the SLO delete
+                if query:
+                    try:
+                        delete_result = json.loads(resp.body)
+                        if delete_result['Errors']:
+                            # NB: bulk includes 404s in "Number Not Found",
+                            # not "Errors"
+                            msg_parts = [delete_result['Response Status']]
+                            msg_parts.extend(
+                                '%s: %s' % (obj, status)
+                                for obj, status in delete_result['Errors'])
+                            return key, {'code': 'SLODeleteError',
+                                         'message': '\n'.join(msg_parts)}
+                        # else, all good
+                    except (ValueError, TypeError, KeyError):
+                        # Logs get all the gory details
+                        self.logger.exception(
+                            'Could not parse SLO delete response: %r',
+                            resp.body)
+                        # Client gets something more generic
+                        return key, {'code': 'SLODeleteError',
+                                     'message': 'Unexpected swift response'}
             except NoSuchKey:
                 pass
             except ErrorResponse as e:
diff --git a/test/functional/s3api/test_multi_upload.py b/test/functional/s3api/test_multi_upload.py
index 15f4b84401..3fed5fb571 100644
--- a/test/functional/s3api/test_multi_upload.py
+++ b/test/functional/s3api/test_multi_upload.py
@@ -32,7 +32,8 @@ from swift.common.middleware.s3api.utils import mktime
 
 from test.functional.s3api import S3ApiBase
 from test.functional.s3api.s3_test_client import Connection
-from test.functional.s3api.utils import get_error_code, get_error_msg
+from test.functional.s3api.utils import get_error_code, get_error_msg, \
+    calculate_md5
 
 
 def setUpModule():
@@ -907,6 +908,27 @@ class TestS3ApiMultiUploadSigV4(TestS3ApiMultiUpload):
         self.assertEqual(status, 200)  # sanity
         self.assertEqual(content, body)  # sanity
 
+        # Can delete it with DeleteMultipleObjects request
+        elem = Element('Delete')
+        SubElement(elem, 'Quiet').text = 'true'
+        obj_elem = SubElement(elem, 'Object')
+        SubElement(obj_elem, 'Key').text = key
+        body = tostring(elem, use_s3ns=False)
+
+        status, headers, body = self.conn.make_request(
+            'POST', bucket, body=body, query='delete',
+            headers={'Content-MD5': calculate_md5(body)})
+        self.assertEqual(status, 200)
+        self.assertCommonResponseHeaders(headers)
+
+        status, headers, body = \
+            self.conn.make_request('GET', bucket, key)
+        self.assertEqual(status, 404)  # sanity
+
+        # Now we can delete
+        status, headers, body = \
+            self.conn.make_request('DELETE', bucket)
+        self.assertEqual(status, 204)  # sanity
 
 if __name__ == '__main__':
     unittest2.main()
diff --git a/test/unit/common/middleware/s3api/test_multi_delete.py b/test/unit/common/middleware/s3api/test_multi_delete.py
index 69241d9295..c8bb7206f6 100644
--- a/test/unit/common/middleware/s3api/test_multi_delete.py
+++ b/test/unit/common/middleware/s3api/test_multi_delete.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import json
 import unittest
 from datetime import datetime
 from hashlib import md5
@@ -64,8 +65,15 @@ class TestS3ApiMultiDelete(S3ApiTestCase):
                             swob.HTTPNoContent, {}, None)
         self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key2',
                             swob.HTTPNotFound, {}, None)
+        slo_delete_resp = {
+            'Number Not Found': 0,
+            'Response Status': '200 OK',
+            'Errors': [],
+            'Response Body': '',
+            'Number Deleted': 8
+        }
         self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key3',
-                            swob.HTTPOk, {}, None)
+                            swob.HTTPOk, {}, json.dumps(slo_delete_resp))
 
         elem = Element('Delete')
         for key in ['Key1', 'Key2', 'Key3']:
@@ -97,15 +105,31 @@ class TestS3ApiMultiDelete(S3ApiTestCase):
 
     @s3acl
     def test_object_multi_DELETE_with_error(self):
-        self.swift.register('HEAD', '/v1/AUTH_test/bucket/Key3',
-                            swob.HTTPForbidden, {}, None)
         self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key1',
                             swob.HTTPNoContent, {}, None)
         self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key2',
                             swob.HTTPNotFound, {}, None)
+        self.swift.register('HEAD', '/v1/AUTH_test/bucket/Key3',
+                            swob.HTTPForbidden, {}, None)
+        self.swift.register('HEAD', '/v1/AUTH_test/bucket/Key4',
+                            swob.HTTPOk,
+                            {'x-static-large-object': 'True'},
+                            None)
+        slo_delete_resp = {
+            'Number Not Found': 0,
+            'Response Status': '400 Bad Request',
+            'Errors': [
+                ["/bucket+segments/obj1", "403 Forbidden"],
+                ["/bucket+segments/obj2", "403 Forbidden"]
+            ],
+            'Response Body': '',
+            'Number Deleted': 8
+        }
+        self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key4',
+                            swob.HTTPOk, {}, json.dumps(slo_delete_resp))
 
         elem = Element('Delete')
-        for key in ['Key1', 'Key2', 'Key3']:
+        for key in ['Key1', 'Key2', 'Key3', 'Key4']:
             obj = SubElement(elem, 'Object')
             SubElement(obj, 'Key').text = key
         body = tostring(elem, use_s3ns=False)
@@ -123,13 +147,24 @@ class TestS3ApiMultiDelete(S3ApiTestCase):
 
         elem = fromstring(body)
         self.assertEqual(len(elem.findall('Deleted')), 2)
-        self.assertEqual(len(elem.findall('Error')), 1)
+        self.assertEqual(len(elem.findall('Error')), 2)
+        self.assertEqual(
+            [(el.find('Code').text, el.find('Message').text)
+             for el in elem.findall('Error')],
+            [('AccessDenied', 'Access Denied.'),
+             ('SLODeleteError', '\n'.join([
+                 '400 Bad Request',
+                 '/bucket+segments/obj1: 403 Forbidden',
+                 '/bucket+segments/obj2: 403 Forbidden']))]
+        )
         self.assertEqual(self.swift.calls, [
             ('HEAD', '/v1/AUTH_test/bucket'),
             ('HEAD', '/v1/AUTH_test/bucket/Key1'),
             ('DELETE', '/v1/AUTH_test/bucket/Key1'),
             ('HEAD', '/v1/AUTH_test/bucket/Key2'),
             ('HEAD', '/v1/AUTH_test/bucket/Key3'),
+            ('HEAD', '/v1/AUTH_test/bucket/Key4'),
+            ('DELETE', '/v1/AUTH_test/bucket/Key4?multipart-manifest=delete'),
         ])
 
     @s3acl