diff --git a/changelogs/unreleased/gh-4348-transactional-ddl.md b/changelogs/unreleased/gh-4348-transactional-ddl.md
new file mode 100644
index 0000000000000000000000000000000000000000..7bb0c046853afee996cd1bace73b7dcc232cf0d5
--- /dev/null
+++ b/changelogs/unreleased/gh-4348-transactional-ddl.md
@@ -0,0 +1,4 @@
+## bugfix/box
+
+* All DDL functions from the `box.schema` module are now wrapped into a
+  transaction to avoid database inconsistency on failed operations (gh-4348).
diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index 87f931ca43536a6d8441a6910befd0924faf7796..d7043b06740788daab1c61421425e0b50170c4a4 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -382,6 +382,18 @@ box.atomic = function(arg0, arg1, ...)
     end
 end
 
+-- Wrap a function into transaction if none is active.
+local function atomic_wrapper(func)
+    return function(...)
+        -- No reason to start a transaction if one is active already.
+        if box.is_in_txn() then
+            return func(...)
+        else
+            return box.atomic(func, ...)
+        end
+    end
+end
+
 -- box.commit yields, so it's defined as Lua/C binding
 -- box.rollback and box.rollback_to_savepoint yields as well
 
@@ -820,7 +832,7 @@ end
 
 box.schema.create_space = box.schema.space.create
 
-box.schema.space.drop = function(space_id, space_name, opts)
+box.schema.space.drop = atomic_wrapper(function(space_id, space_name, opts)
     check_param(space_id, 'space_id', 'number')
     opts = opts or {}
     check_param_table(opts, { if_exists = 'boolean' })
@@ -872,7 +884,7 @@ box.schema.space.drop = function(space_id, space_name, opts)
     end
 
     feedback_save_event('drop_space')
-end
+end)
 
 box.schema.space.rename = function(space_id, space_name)
     check_param(space_id, 'space_id', 'number')
@@ -1252,10 +1264,9 @@ local function space_sequence_check(sequence, parts, space_name, index_name)
 end
 
 --
--- The first stage of a space sequence modification operation.
--- Called before altering the space definition. Checks sequence
--- options and detaches the old sequence from the space.
--- Returns a proxy object that is supposed to be passed to
+-- The first stage of a space sequence modification operation. Called
+-- before altering the space definition. Checks sequence options and
+-- returns a proxy object that is supposed to be passed to the
 -- space_sequence_alter_commit() to complete the operation.
 --
 local function space_sequence_alter_prepare(format, parts, options,
@@ -1361,11 +1372,6 @@ local function space_sequence_alter_prepare(format, parts, options,
         new_sequence.is_generated = new_sequence.is_generated or false
     end
 
-    if old_sequence ~= nil then
-        -- Detach the old sequence before altering the space.
-        _space_sequence:delete(space_id)
-    end
-
     return {
         space_id = space_id,
         new_sequence = new_sequence,
@@ -1374,9 +1380,9 @@ local function space_sequence_alter_prepare(format, parts, options,
 end
 
 --
--- The second stage of a space sequence modification operation.
--- Called after altering the space definition. Attaches the sequence
--- to the space and drops the old sequence if required. 'proxy' is
+-- The second stage of a space sequence modification operation. Called after
+-- altering the space definition. Detaches the old sequence from the space and
+-- attaches the new one to it. Drops the old sequence if required. 'proxy' is
 -- an object returned by space_sequence_alter_prepare().
 --
 local function space_sequence_alter_commit(proxy)
@@ -1391,6 +1397,10 @@ local function space_sequence_alter_commit(proxy)
     local old_sequence = proxy.old_sequence
     local new_sequence = proxy.new_sequence
 
+    if old_sequence ~= nil then
+        _space_sequence:delete(space_id)
+    end
+
     if new_sequence ~= nil then
         -- Attach the new sequence.
         _space_sequence:insert{space_id, new_sequence.id,
@@ -1476,7 +1486,7 @@ local function func_id_by_name(func_name)
 end
 box.internal.func_id_by_name = func_id_by_name -- for space.upgrade
 
-box.schema.index.create = function(space_id, name, options)
+box.schema.index.create = atomic_wrapper(function(space_id, name, options)
     check_param(space_id, 'space_id', 'number')
     check_param(name, 'name', 'string')
     check_param_table(options, create_index_template)
@@ -1599,9 +1609,9 @@ box.schema.index.create = function(space_id, name, options)
 
     feedback_save_event('create_index')
     return space.index[name]
-end
+end)
 
-box.schema.index.drop = function(space_id, index_id)
+box.schema.index.drop = atomic_wrapper(function(space_id, index_id)
     check_param(space_id, 'space_id', 'number')
     check_param(index_id, 'index_id', 'number')
     if index_id == 0 then
@@ -1625,7 +1635,7 @@ box.schema.index.drop = function(space_id, index_id)
     _index:delete{space_id, index_id}
 
     feedback_save_event('drop_index')
-end
+end)
 
 box.schema.index.rename = function(space_id, index_id, name)
     check_param(space_id, 'space_id', 'number')
@@ -1636,7 +1646,7 @@ box.schema.index.rename = function(space_id, index_id, name)
     _index:update({space_id, index_id}, {{"=", 3, name}})
 end
 
-box.schema.index.alter = function(space_id, index_id, options)
+box.schema.index.alter = atomic_wrapper(function(space_id, index_id, options)
     local space = box.space[space_id]
     if space == nil then
         box.error(box.error.NO_SUCH_SPACE, '#'..tostring(space_id))
@@ -1739,7 +1749,7 @@ box.schema.index.alter = function(space_id, index_id, options)
         _func_index:insert{space_id, index_id, index_opts.func}
     end
     space_sequence_alter_commit(sequence_proxy)
-end
+end)
 
 -- a static box_tuple_t ** instance for calling box_index_* API
 local ptuple = ffi.new('box_tuple_t *[1]')
@@ -2850,7 +2860,7 @@ box.schema.sequence.alter = function(name, opts)
                       opts.max, opts.start, opts.cache, opts.cycle}
 end
 
-box.schema.sequence.drop = function(name, opts)
+box.schema.sequence.drop = atomic_wrapper(function(name, opts)
     opts = opts or {}
     check_param_table(opts, {if_exists = 'boolean'})
     local id = sequence_resolve(name)
@@ -2865,7 +2875,7 @@ box.schema.sequence.drop = function(name, opts)
     local _sequence_data = box.space[box.schema.SEQUENCE_DATA_ID]
     _sequence_data:delete{id}
     _sequence:delete{id}
-end
+end)
 
 local function privilege_parse(privs)
     -- TODO: introduce a global privilege -> bit mapping?
@@ -3142,7 +3152,7 @@ box.schema.func.create = function(name, opts)
                          opts.comment, opts.created, opts.last_altered}
 end
 
-box.schema.func.drop = function(name, opts)
+box.schema.func.drop = atomic_wrapper(function(name, opts)
     opts = opts or {}
     check_param_table(opts, { if_exists = 'boolean' })
     local _func = box.space[box.schema.FUNC_ID]
@@ -3165,7 +3175,7 @@ box.schema.func.drop = function(name, opts)
     end
     revoke_object_privs('function', fid)
     _func:delete{fid}
-end
+end)
 
 function box.schema.func.exists(name_or_id)
     local _vfunc = box.space[box.schema.VFUNC_ID]
@@ -3326,7 +3336,7 @@ box.schema.user.passwd = function(name, new_password)
     end
 end
 
-box.schema.user.create = function(name, opts)
+box.schema.user.create = atomic_wrapper(function(name, opts)
     local uid = user_or_role_resolve(name)
     opts = opts or {}
     check_param_table(opts, { password = 'string', if_not_exists = 'boolean' })
@@ -3356,7 +3366,7 @@ box.schema.user.create = function(name, opts)
     -- grant option
     box.session.su('admin', box.schema.user.grant, uid, 'session,usage', 'universe',
                    nil, {if_not_exists=true})
-end
+end)
 
 box.schema.user.exists = function(name)
     if user_resolve(name) then
@@ -3542,7 +3552,7 @@ box.schema.user.disable = function(user)
                             {if_exists = true})
 end
 
-box.schema.user.drop = function(name, opts)
+box.schema.user.drop = atomic_wrapper(function(name, opts)
     opts = opts or {}
     check_param_table(opts, { if_exists = 'boolean' })
     local uid = user_resolve(name)
@@ -3563,7 +3573,7 @@ box.schema.user.drop = function(name, opts)
         box.error(box.error.NO_SUCH_USER, name)
     end
     return
-end
+end)
 
 local function info(id)
     local _priv = box.space._vpriv
@@ -3616,7 +3626,7 @@ box.schema.role.create = function(name, opts)
                          math.floor(fiber.time())}
 end
 
-box.schema.role.drop = function(name, opts)
+box.schema.role.drop = atomic_wrapper(function(name, opts)
     opts = opts or {}
     check_param_table(opts, { if_exists = 'boolean' })
     local uid = role_resolve(name)
@@ -3632,7 +3642,7 @@ box.schema.role.drop = function(name, opts)
         box.error(box.error.DROP_USER, name, "the user or the role is a system")
     end
     return drop(uid)
-end
+end)
 
 local function role_check_grant_revoke_of_sys_priv(priv)
     priv = string.lower(priv)
diff --git a/test/box-luatest/builtin_events_test.lua b/test/box-luatest/builtin_events_test.lua
index 9e37097b1378060c32af2259770a5ca6d10c9ba0..bba16da828f6c5752ab591fcbd2f6550c18d1d40 100644
--- a/test/box-luatest/builtin_events_test.lua
+++ b/test/box-luatest/builtin_events_test.lua
@@ -278,7 +278,7 @@ g.test_box_schema = function(cg)
 
     version_n = 0
     cg.master:exec(function() box.space.p:drop() end)
-    t.helpers.retrying({}, function() t.assert_equals(version_n, 2) end)
+    t.helpers.retrying({}, function() t.assert_equals(version_n, 1) end)
     -- there'll be 2 changes - index and space
     t.assert_equals(version, init_version + 4)
 
diff --git a/test/box-luatest/gh_4348_transactional_ddl_test.lua b/test/box-luatest/gh_4348_transactional_ddl_test.lua
new file mode 100644
index 0000000000000000000000000000000000000000..cbaf96b813cf8323d97d0121fbac1788e9d3ed1c
--- /dev/null
+++ b/test/box-luatest/gh_4348_transactional_ddl_test.lua
@@ -0,0 +1,271 @@
+local server = require('luatest.server')
+local t = require('luatest')
+
+local g = t.group('gh-4348-transactional-ddl-test',
+    t.helpers.matrix({mvcc = {true, false}}))
+
+g.before_all(function(cg)
+    cg.server = server:new({
+        box_cfg = {memtx_use_mvcc_engine = cg.params.mvcc}
+    })
+    cg.server:start()
+end)
+
+g.after_all(function(cg)
+    cg.server:drop()
+end)
+
+g.after_each(function(cg)
+    cg.server:exec(function()
+        if box.space.s ~= nil then
+            box.space.s:drop()
+        end
+        if box.space.s2 ~= nil then
+            box.space.s2:drop()
+        end
+        box.schema.func.drop('f', {if_exists = true})
+        box.schema.sequence.drop('seq', {if_exists = true})
+        box.schema.user.drop('new_user', {if_exists = true})
+        box.schema.user.drop('new_user_2', {if_exists = true})
+    end)
+end)
+
+g.test_atomic_space_drop = function(cg)
+    cg.server:exec(function()
+        local s = box.schema.space.create('s')
+        local s2 = box.schema.space.create('s2')
+
+        s:create_index('pk')
+        s2:create_index('pk')
+
+        local s2sk = s2:create_index('sk')
+
+        s2:insert({2})
+        s:insert({1, 2})
+
+        box.schema.space.alter(s.id, {foreign_key = {
+            f1 = {space = s2.name, field = {[2] = 1}},
+        }})
+
+        -- Attempt tp drop a referenced foreign key space with secondary
+        -- indexes.
+        --
+        -- Currently the space drop flow looks like this:
+        -- 1. Drop automatically generated sequence for the space.
+        -- 2. Drop triggers of the space.
+        -- 3. Disable functional indexes of the space.
+        -- 4. (!) Remove each index of the space starting from secondary
+        --    indexes.
+        -- 5. Revoke the space privileges.
+        -- 6. Remove the associated entry from the _truncate system space.
+        -- 7. Remove the space entry from _space system space.
+        --
+        -- If the space is referenced by another space with foreign key
+        -- constraint then the flow fails on the primary index drop (step 4).
+        -- But at that point all the secondary indexes are dropped already, so
+        -- we have an inconsistent state of the database.
+        --
+        -- But if the drop function is transactional then the dropped secondary
+        -- indexes are restored on transaction revert and the database remains
+        -- consistent: we can continue using the secondary index of the table we
+        -- have failed to drop.
+
+        local err = "Can't modify space '" .. s2.name
+                    .. "': space is referenced by foreign key"
+        t.assert_error_msg_equals(err, s2.drop, s2)
+
+        -- The secondary index is restored on drop fail so this must succeed.
+        s2sk:select(42)
+    end)
+end
+
+
+g.test_atomic_index_create = function(cg)
+    cg.server:exec(function()
+        local s = box.schema.space.create('s')
+        s:create_index('pk', {parts = {{1, 'scalar'}}})
+
+        -- Currently on the index creation _func_index entry is created after
+        -- the _index space is modified, so if the error is thrown on performing
+        -- function ID check, the new index is registered already.
+        --
+        -- If the index creation is not transactional then we gonna have a new
+        -- disabled functional index. But if it is then the index creation is
+        -- rolled back.
+
+        local err = "Function '42' does not exist"
+        t.assert_error_msg_equals(err, s.create_index, s, 'fk', {func = 42})
+
+        -- The created index should be dropped if the index creation is atomic.
+        t.assert_equals(box.space.s.index.fk, nil)
+    end)
+end
+
+-- The index drop is not testable without error injection.
+
+g.test_atomic_index_alter = function(cg)
+    cg.server:exec(function()
+        local s = box.schema.space.create('s')
+        s:create_index('pk', {parts = {{1, 'scalar'}}})
+        local sk = s:create_index('sk')
+
+        -- Currently on the index alter _func_index entry is created after the
+        -- _index space is modified, so if the error is thrown on performing
+        -- function ID check, the index is altered already.
+        --
+        -- If the index creation is not transactional then we gonna have a
+        -- disabled functional index. But if it is then the index alter is
+        -- rolled back.
+
+        local err = "Function '42' does not exist"
+        t.assert_error_msg_equals(err, sk.alter, sk, {name = 'fk', func = 42})
+
+        -- The index name should be reverted if the index alter is atomic.
+        t.assert_equals(box.space.s.index[1].name, 'sk')
+    end)
+end
+
+g.test_atomic_sequence_drop = function(cg)
+    cg.server:exec(function()
+        local s = box.schema.space.create('s')
+        s:create_index('pk', {sequence = true})
+
+        -- The sequence drop routine first drops the corresponding entry from
+        -- the _sequence_data space and then drops the sequence itself. So
+        -- if the routine is not atomic we will observe the sequence reset
+        -- on failed attempt to drop it. If it's not - the sequence data will
+        -- be restored.
+
+        -- Create an entry in the _sequence_data.
+        box.space._sequence_data:insert({1, 42})
+
+        -- Attempt to drop the sequence which is in use by the 's' space.
+        local err = "Can't drop sequence 's_seq': the sequence is in use"
+        t.assert_error_msg_equals(err, box.schema.sequence.drop, 's_seq')
+
+        -- The dropped _sequence_data entry should be restored.
+        t.assert_equals(box.space._sequence_data:select(), {{1, 42}})
+
+        -- A new item should have the correct ID (which is 43).
+        t.assert_equals(s:insert({nil, 1})[1], 43)
+    end)
+end
+
+g.test_atomic_func_drop = function(cg)
+    cg.server:exec(function()
+        local s = box.schema.space.create('s')
+        s:create_index('pk')
+
+        box.schema.func.create('f', {
+            language = 'LUA',
+            is_deterministic = true,
+            is_sandboxed = true,
+            body = 'function() return {1} end'
+        })
+
+        -- Use the function in a functional index.
+        s:create_index('fk', {func = 'f'})
+
+        -- Add an entry to the _priv space.
+        box.schema.user.grant('admin', 'execute', 'function', 'f')
+
+        -- Attempt to drop the function which is in use.
+        local err = "function has references"
+        t.assert_error_msg_contains(err, box.schema.func.drop, 'f')
+
+        -- Check if the dropped privileges had been restored. If it's not the
+        -- case then the following privilege revocation will fail.
+        box.schema.user.revoke('admin', 'execute', 'function', 'f')
+    end)
+end
+
+g.test_atomic_user_create = function(cg)
+    cg.server:exec(function()
+        -- Nothing should be there yet.
+        t.assert_equals(box.space.s, nil)
+        t.assert_equals(box.schema.user.exists('new_user'), false)
+
+        -- The user creation procedure includes creation of an entry in the
+        -- _user space and granting him some privileges. In case if the user
+        -- creator does not have rights to grant privilegies to other users
+        -- then the privilege granting part will fail.
+        --
+        -- In order to check that the creation is atomic, we create a user
+        -- unable to grant ay privileges to any other user and so we make
+        -- the user creation fail on privilege grant part. The created user
+        -- should be dropped on the transaction rollback.
+
+        local original_user = box.session.euid()
+
+        -- Create a new user that can't grant any privileges.
+        box.session.su('admin')
+        box.schema.user.create('new_user')
+        box.schema.user.grant('new_user', 'read,write', 'space', '_user')
+        box.schema.user.grant('new_user', 'create', 'user')
+
+        -- Attempt to create a used by this user will fail on privilege
+        -- assignment stage, because he can't access the _priv space.
+        box.session.su('new_user')
+        local err = "Write access to space '_priv' is denied for user"
+        t.assert_error_msg_contains(err, box.schema.user.create, 'new_user_2')
+
+        box.session.su(original_user)
+
+        -- Check if the new user had been dropped after transaction rollback.
+        t.assert_equals(box.schema.user.exists('new_user_2'), false)
+    end)
+end
+
+-- box.schema.role.drop is a variation of box.schema.user.drop.
+g.test_atomic_user_drop = function(cg)
+    cg.server:exec(function()
+        -- Nothing should be there yet.
+        t.assert_equals(box.space.s, nil)
+        t.assert_equals(box.sequence.seq, nil)
+        t.assert_equals(box.schema.user.exists('new_user'), false)
+
+        -- The user drop is not just removal of an entry from the _user space.
+        -- All the objects created by the user should be dropped too, including
+        -- (but not limited to) spaces and sequences.
+        --
+        -- The spaces are dropped first, and, at some point later, we drop the
+        -- user's sequences. That means in case if the user drop is not atomic,
+        -- then it's possible the situation when we succeed to drop all spaces,
+        -- but failed to drop a sequence. In this case we are going to have an
+        -- inconsistent state: the changes are partially applied.
+        --
+        -- So here we create a user, make him create a space and a sequence, and
+        -- then, in order to make the sequence drop fail, we use the sequence in
+        -- an admin's space. So attempt drop a user will cause the sequence drop
+        -- which will fail, because the sequence is in use by admin's space.
+        --
+        -- In order to check that the drop is atomic, we check if the space that
+        -- had been dropped within the transaction, will still be there once the
+        -- transaction is rolled back on failure.
+
+        -- Create a new user and make him create a new space and sequence.
+        local original_user = box.session.euid()
+        box.session.su('admin')
+        box.schema.user.create('new_user')
+        box.schema.user.grant('new_user',
+                              'create,drop,read,write,execute', 'universe')
+        box.session.su('new_user', box.schema.space.create, 's')
+        box.session.su('new_user', box.schema.sequence.create, 'seq')
+        box.session.su(original_user)
+
+        -- Use the sequence created by the new user.
+        local s2 = box.schema.space.create('s2')
+        s2:create_index('pk', {sequence = 'seq'})
+
+        -- Attempt to drop the user will fail, because it drops everything that
+        -- had been created by the user, including sequences. But the sequence
+        -- created by the user is used by admin in his space.
+        local err = "Can't drop sequence 'seq': the sequence is in use"
+        t.assert_error_msg_equals(err, box.schema.user.drop, 'new_user')
+
+        -- The sequence drop attempt happens after drop of all user spaces, but
+        -- the dropped space should be recovered by the rollback if the space
+        -- drop is transactional.
+        t.assert_not_equals(box.space.s, nil)
+    end)
+end
diff --git a/test/box/errinj.result b/test/box/errinj.result
index 6c2dd1ea276b8384fe6056a0fdab4b0df217e046..7af6163f7dabb602640b081e570b0babed52edf7 100644
--- a/test/box/errinj.result
+++ b/test/box/errinj.result
@@ -415,6 +415,11 @@ s_withdata:drop()
 ---
 - error: Failed to write to disk
 ...
+-- FIXME(gh-9120): The space is recreated, so the s_withdata object is not
+-- valid anymore.
+s_withdata = box.space.withdata
+---
+...
 box.space['withdata'].enabled
 ---
 - true
@@ -1335,6 +1340,11 @@ s:drop()
 ---
 - error: Failed to write to disk
 ...
+-- FIXME(gh-9120): The space object is invalidated on reverted drop, so we set
+-- it to the current one.
+s = box.space.test
+---
+...
 s:truncate()
 ---
 - error: Failed to write to disk
diff --git a/test/box/errinj.test.lua b/test/box/errinj.test.lua
index 78047408d658ecca8a98ab04352b2d26e13c21f6..e2219529fa63bb13616a1947a8dbcea42825fd36 100644
--- a/test/box/errinj.test.lua
+++ b/test/box/errinj.test.lua
@@ -100,6 +100,9 @@ s_withindex.index.secondary
 s_withdata.index.secondary:drop()
 s_withdata.index.secondary.unique
 s_withdata:drop()
+-- FIXME(gh-9120): The space is recreated, so the s_withdata object is not
+-- valid anymore.
+s_withdata = box.space.withdata
 box.space['withdata'].enabled
 index4 = s_withdata:create_index('another', { type = 'tree', parts = { 5, 'unsigned' }, unique = false})
 s_withdata.index.another
@@ -447,6 +450,9 @@ errinj.set('ERRINJ_WAL_IO', true)
 s:drop()
 s:truncate()
 s:drop()
+-- FIXME(gh-9120): The space object is invalidated on reverted drop, so we set
+-- it to the current one.
+s = box.space.test
 s:truncate()
 errinj.set('ERRINJ_WAL_IO', false)
 for i = 1, 10 do s:replace{i + 10} end
diff --git a/test/box/sequence.result b/test/box/sequence.result
index b49540983a97f6232f2d9896bd7aab302ff92ff3..08036091596062ae0289524dbb5f06ee3a6250c0 100644
--- a/test/box/sequence.result
+++ b/test/box/sequence.result
@@ -1722,7 +1722,7 @@ box.space._space_sequence:replace{s2.id, sq1.id, false, 0, ''} -- error
 ---
 - error: Read access to sequence 'seq1' is denied for user 'user'
 ...
-s2.index.pk:alter({sequence = 'seq2'}) -- ok
+_ = s2:create_index('pk', {sequence = 'seq2'}) -- ok
 ---
 ...
 box.session.su('admin')
diff --git a/test/box/sequence.test.lua b/test/box/sequence.test.lua
index 21a56f5b460e7bc05c52d15fd5d9515aa958d549..0b7b411f485b7343404438509d29b41acd4f5224 100644
--- a/test/box/sequence.test.lua
+++ b/test/box/sequence.test.lua
@@ -569,7 +569,7 @@ s1.index.pk:alter({sequence = 'seq1'}) -- error
 box.space._space_sequence:replace{s1.id, sq1.id, false, 0, ''} -- error
 box.space._space_sequence:replace{s1.id, sq2.id, false, 0, ''} -- error
 box.space._space_sequence:replace{s2.id, sq1.id, false, 0, ''} -- error
-s2.index.pk:alter({sequence = 'seq2'}) -- ok
+_ = s2:create_index('pk', {sequence = 'seq2'}) -- ok
 box.session.su('admin')
 
 -- If the user owns a sequence attached to a space,
diff --git a/test/engine-luatest/gh_6436_complex_foreign_key_test.lua b/test/engine-luatest/gh_6436_complex_foreign_key_test.lua
index 9a26e28516a5cb8694a964a1788a65a83db9af42..2a0a4f517b492460bc351025edacf4e202471b2c 100644
--- a/test/engine-luatest/gh_6436_complex_foreign_key_test.lua
+++ b/test/engine-luatest/gh_6436_complex_foreign_key_test.lua
@@ -109,7 +109,7 @@ g.test_complex_foreign_key_primary = function(cg)
         t.assert_equals(country:select{}, {{1, 11, 'Russia'}, {1, 12, 'France'}})
         t.assert_error_msg_content_equals(
             "Can't modify space 'country': space is referenced by foreign key",
-            box.atomic, country.drop, country
+            country.drop, country
         )
         t.assert_error_msg_content_equals(
             "Foreign key 'country' integrity check failed: wrong foreign field name",
@@ -198,7 +198,7 @@ g.test_complex_foreign_key_secondary = function(cg)
                                            {101, 1, 'earth', 'rf', 'France'}})
         t.assert_error_msg_content_equals(
             "Can't modify space 'country': space is referenced by foreign key",
-            box.atomic, country.drop, country
+            country.drop, country
         )
         t.assert_equals(country:select{}, {{100, 1, 'earth', 'ru', 'Russia'},
                                            {101, 1, 'earth', 'rf', 'France'}})
@@ -293,7 +293,7 @@ g.test_complex_foreign_key_numeric = function(cg)
                                            {101, 1, 'earth', 'rf', 'France'}})
         t.assert_error_msg_content_equals(
             "Can't modify space 'country': space is referenced by foreign key",
-            box.atomic, country.drop, country
+            country.drop, country
         )
         t.assert_equals(country:select{}, {{100, 1, 'earth', 'ru', 'Russia'},
                                            {101, 1, 'earth', 'rf', 'France'}})
diff --git a/test/engine-luatest/gh_6436_field_foreign_key_test.lua b/test/engine-luatest/gh_6436_field_foreign_key_test.lua
index bdb04acde40606513d0fce15761061827655948e..c6a34a7ac9ca410cfae6a15f05633058a1b028de 100644
--- a/test/engine-luatest/gh_6436_field_foreign_key_test.lua
+++ b/test/engine-luatest/gh_6436_field_foreign_key_test.lua
@@ -137,7 +137,7 @@ g.test_foreign_key_primary = function(cg)
         t.assert_equals(country:select{}, {{1, 'ru', 'Russia'}, {2, 'fr', 'France'}})
         t.assert_error_msg_content_equals(
             "Can't modify space 'country': space is referenced by foreign key",
-            box.atomic, country.drop, country
+            country.drop, country
         )
         t.assert_equals(country:select{}, {{1, 'ru', 'Russia'}, {2, 'fr', 'France'}})
         t.assert_error_msg_content_equals(
@@ -215,7 +215,7 @@ g.test_foreign_key_secondary = function(cg)
         t.assert_equals(country:select{}, {{1, 'ru', 'Russia'}, {2, 'fr', 'France'}})
         t.assert_error_msg_content_equals(
             "Can't modify space 'country': space is referenced by foreign key",
-            box.atomic, country.drop, country
+            country.drop, country
         )
         t.assert_equals(country:select{}, {{1, 'ru', 'Russia'}, {2, 'fr', 'France'}})
         t.assert_error_msg_content_equals(
@@ -297,7 +297,7 @@ g.test_foreign_key_numeric = function(cg)
         t.assert_equals(country:select{}, {{1, 'ru', 'Russia'}, {2, 'fr', 'France'}})
         t.assert_error_msg_content_equals(
             "Can't modify space 'country': space is referenced by foreign key",
-            box.atomic, country.drop, country
+            country.drop, country
         )
         t.assert_equals(country:select{}, {{1, 'ru', 'Russia'}, {2, 'fr', 'France'}})
         t.assert_error_msg_content_equals(
diff --git a/test/engine/func_index.result b/test/engine/func_index.result
index 40573bbfb0ad93a88a3b024b66c216d01bfd22d6..fc7166afc4e95176f332fe4c1207c5778da68f45 100644
--- a/test/engine/func_index.result
+++ b/test/engine/func_index.result
@@ -57,9 +57,6 @@ _ = s:create_index('idx', {func = 6666, parts = {{1, 'unsigned'}}})
  | ---
  | - error: Function '6666' does not exist
  | ...
-s.index.idx:drop()
- | ---
- | ...
 -- Can't use non-persistent function in functional index.
 _ = s:create_index('idx', {func = box.func.s_nonpersistent.id, parts = {{1, 'unsigned'}}})
  | ---
diff --git a/test/engine/func_index.test.lua b/test/engine/func_index.test.lua
index 3b48bb478f8428e1bb7a1462ccf5cd9ea2274ed9..8b267697056bca26c3981f7b137136db6f2eff97 100644
--- a/test/engine/func_index.test.lua
+++ b/test/engine/func_index.test.lua
@@ -21,7 +21,6 @@ _ = s:create_index('idx', {func = box.func.s.id, parts = {{1, 'unsigned'}}})
 pk = s:create_index('pk')
 -- Invalid fid.
 _ = s:create_index('idx', {func = 6666, parts = {{1, 'unsigned'}}})
-s.index.idx:drop()
 -- Can't use non-persistent function in functional index.
 _ = s:create_index('idx', {func = box.func.s_nonpersistent.id, parts = {{1, 'unsigned'}}})
 -- Can't use non-deterministic function in functional index.
diff --git a/test/sql/no-pk-space.result b/test/sql/no-pk-space.result
index 12f2407d8001542576a714067bd1728ea84ba380..e7f79da014d81d5804fa9acf6d4a057ebb899358 100644
--- a/test/sql/no-pk-space.result
+++ b/test/sql/no-pk-space.result
@@ -39,30 +39,3 @@ box.execute("UPDATE \"test\" SET id = 3;")
 s:drop()
 ---
 ...
--- Notorious artefact: check of view referencing counter occurs
--- after drop of indexes. So, if space:drop() fails due to being
--- referenced by a view, space becomes unusable in SQL terms.
---
-box.execute("CREATE TABLE t1 (id INT PRIMARY KEY);")
----
-- row_count: 1
-...
-box.execute("CREATE VIEW v1 AS SELECT * FROM t1;")
----
-- row_count: 1
-...
-box.space.T1:drop()
----
-- error: 'Can''t drop space ''T1'': other views depend on this space'
-...
-box.execute("SELECT * FROM v1;")
----
-- null
-- SQL does not support spaces without primary key
-...
-box.space.V1:drop()
----
-...
-box.space.T1:drop()
----
-...
diff --git a/test/sql/no-pk-space.test.lua b/test/sql/no-pk-space.test.lua
index d7f947921341206eceee7dba1ccb37d508fe7862..7e02b9beec91a5699692e319f31e37dee7a65780 100644
--- a/test/sql/no-pk-space.test.lua
+++ b/test/sql/no-pk-space.test.lua
@@ -11,14 +11,3 @@ box.execute("DELETE FROM \"test\";")
 box.execute("UPDATE \"test\" SET id = 3;")
 
 s:drop()
-
--- Notorious artefact: check of view referencing counter occurs
--- after drop of indexes. So, if space:drop() fails due to being
--- referenced by a view, space becomes unusable in SQL terms.
---
-box.execute("CREATE TABLE t1 (id INT PRIMARY KEY);")
-box.execute("CREATE VIEW v1 AS SELECT * FROM t1;")
-box.space.T1:drop()
-box.execute("SELECT * FROM v1;")
-box.space.V1:drop()
-box.space.T1:drop()