diff --git a/builtin/game/register.lua b/builtin/game/register.lua
index f330491a21cf797be12db5c6895c444e9be3fcc3..05dc5fef83da73be5243b27fc0d4f640861ecd4d 100644
--- a/builtin/game/register.lua
+++ b/builtin/game/register.lua
@@ -7,6 +7,9 @@
 local register_item_raw = core.register_item_raw
 core.register_item_raw = nil
 
+local unregister_item_raw = core.unregister_item_raw
+core.unregister_item_raw = nil
+
 local register_alias_raw = core.register_alias_raw
 core.register_alias_raw = nil
 
@@ -172,6 +175,27 @@ function core.register_item(name, itemdef)
 	register_item_raw(itemdef)
 end
 
+function core.unregister_item(name)
+	if not core.registered_items[name] then
+		core.log("warning", "Not unregistering item " ..name..
+			" because it doesn't exist.")
+		return
+	end
+	-- Erase from registered_* table
+	local type = core.registered_items[name].type
+	if type == "node" then
+		core.registered_nodes[name] = nil
+	elseif type == "craft" then
+		core.registered_craftitems[name] = nil
+	elseif type == "tool" then
+		core.registered_tools[name] = nil
+	end
+	core.registered_items[name] = nil
+
+
+	unregister_item_raw(name)
+end
+
 function core.register_node(name, nodedef)
 	nodedef.type = "node"
 	core.register_item(name, nodedef)
@@ -242,6 +266,20 @@ function core.register_alias(name, convert_to)
 	end
 end
 
+function core.register_alias_force(name, convert_to)
+	if forbidden_item_names[name] then
+		error("Unable to register alias: Name is forbidden: " .. name)
+	end
+	if core.registered_items[name] ~= nil then
+		core.unregister_item(name)
+		core.log("info", "Removed item " ..name..
+			" while attempting to force add an alias")
+	end
+	--core.log("Registering alias: " .. name .. " -> " .. convert_to)
+	core.registered_aliases[name] = convert_to
+	register_alias_raw(name, convert_to)
+end
+
 function core.on_craft(itemstack, player, old_craft_list, craft_inv)
 	for _, func in ipairs(core.registered_on_crafts) do
 		itemstack = func(itemstack, player, old_craft_list, craft_inv) or itemstack
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 579fe796e18f30a68657f48ec6df91ffb029626c..da9ebb9f1f8bc485d183040194b1c8f7a1afb065 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -208,11 +208,17 @@ when registering it.
 The `:` prefix can also be used for maintaining backwards compatibility.
 
 ### Aliases
-Aliases can be added by using `minetest.register_alias(name, convert_to)`.
+Aliases can be added by using `minetest.register_alias(name, convert_to)` or
+`minetest.register_alias_force(name, convert_to).
 
 This will make Minetest to convert things called name to things called
 `convert_to`.
 
+The only difference between `minetest.register_alias` and
+`minetest.register_alias_force` is that if an item called `name` exists,
+`minetest.register_alias` will do nothing while
+`minetest.register_alias_force` will unregister it.
+
 This can be used for maintaining backwards compatibility.
 
 This can be also used for setting quick access names for things, e.g. if
@@ -464,6 +470,11 @@ the global `minetest.registered_*` tables.
 * `minetest.register_craftitem(name, item definition)`
     * added to `minetest.registered_items[name]`
 
+* `minetest.unregister_item(name)`
+    * Unregisters the item name from engine, and deletes the entry with key
+    * `name` from `minetest.registered_items` and from the associated item
+    * table according to its nature: minetest.registered_nodes[] etc
+
 * `minetest.register_biome(biome definition)`
     * returns an integer uniquely identifying the registered biome
     * added to `minetest.registered_biome` with the key of `biome.name`
@@ -1883,7 +1894,9 @@ Call these functions only at load time!
 * `minetest.register_node(name, node definition)`
 * `minetest.register_tool(name, item definition)`
 * `minetest.register_craftitem(name, item definition)`
+* `minetest.unregister_item(name)`
 * `minetest.register_alias(name, convert_to)`
+* `minetest.register_alias_force(name, convert_to)`
 * `minetest.register_craft(recipe)`
     * Check recipe table syntax for different types below.
 * `minetest.clear_craft(recipe)`
diff --git a/src/itemdef.cpp b/src/itemdef.cpp
index a618ad631b078666a682ec39d944b129b2096884..a6c627a037a5992639be2848efc6ea780c2434e1 100644
--- a/src/itemdef.cpp
+++ b/src/itemdef.cpp
@@ -466,11 +466,17 @@ class CItemDefManager: public IWritableItemDefManager
 			infostream<<"ItemDefManager: erased alias "<<def.name
 					<<" because item was defined"<<std::endl;
 	}
+	virtual void unregisterItem(const std::string &name)
+	{
+		verbosestream<<"ItemDefManager: unregistering \""<<name<<"\""<<std::endl;
+
+		delete m_item_definitions[name];
+		m_item_definitions.erase(name);
+	}
 	virtual void registerAlias(const std::string &name,
 			const std::string &convert_to)
 	{
-		if(m_item_definitions.find(name) == m_item_definitions.end())
-		{
+		if (m_item_definitions.find(name) == m_item_definitions.end()) {
 			verbosestream<<"ItemDefManager: setting alias "<<name
 				<<" -> "<<convert_to<<std::endl;
 			m_aliases[name] = convert_to;
diff --git a/src/itemdef.h b/src/itemdef.h
index 805b4aa5dd09bfb8b977bad71b93177a4d7bdcef..b14ed41f7f2a5a0b21acea8a436c98db4f454585 100644
--- a/src/itemdef.h
+++ b/src/itemdef.h
@@ -144,6 +144,7 @@ class IWritableItemDefManager : public IItemDefManager
 	virtual void clear()=0;
 	// Register item definition
 	virtual void registerItem(const ItemDefinition &def)=0;
+	virtual void unregisterItem(const std::string &name)=0;
 	// Set an alias so that items named <name> will load as <convert_to>.
 	// Alias is not set if <name> has already been defined.
 	// Alias will be removed if <name> is defined at a later point of time.
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index 646375575d5483946feffe719c3fd9490855ce29..bfb2999bd33bf1bd57f6a8763ec1d0af9c6fd27d 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -778,6 +778,7 @@ class CNodeDefManager: public IWritableNodeDefManager {
 	content_t allocateId();
 	virtual content_t set(const std::string &name, const ContentFeatures &def);
 	virtual content_t allocateDummy(const std::string &name);
+	virtual void removeNode(const std::string &name);
 	virtual void updateAliases(IItemDefManager *idef);
 	virtual void applyTextureOverrides(const std::string &override_filepath);
 	virtual void updateTextures(IGameDef *gamedef,
@@ -1072,6 +1073,40 @@ content_t CNodeDefManager::allocateDummy(const std::string &name)
 }
 
 
+void CNodeDefManager::removeNode(const std::string &name)
+{
+	// Pre-condition
+	assert(name != "");
+
+	// Erase name from name ID mapping
+	content_t id = CONTENT_IGNORE;
+	if (m_name_id_mapping.getId(name, id)) {
+		m_name_id_mapping.eraseName(name);
+		m_name_id_mapping_with_aliases.erase(name);
+	}
+
+	// Erase node content from all groups it belongs to
+	for (std::map<std::string, GroupItems>::iterator iter_groups =
+			m_group_to_items.begin();
+			iter_groups != m_group_to_items.end();) {
+		GroupItems &items = iter_groups->second;
+		for (GroupItems::iterator iter_groupitems = items.begin();
+				iter_groupitems != items.end();) {
+			if (iter_groupitems->first == id)
+				items.erase(iter_groupitems++);
+			else
+				iter_groupitems++;
+		}
+
+		// Check if group is empty
+		if (items.size() == 0)
+			m_group_to_items.erase(iter_groups++);
+		else
+			iter_groups++;
+	}
+}
+
+
 void CNodeDefManager::updateAliases(IItemDefManager *idef)
 {
 	std::set<std::string> all = idef->getAll();
diff --git a/src/nodedef.h b/src/nodedef.h
index f17c53727a6393e5a36688f4fcef795e9267bc9b..80396f992308db095f40871d6ec5a4723286692f 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -384,6 +384,8 @@ class IWritableNodeDefManager : public INodeDefManager {
 			const ContentFeatures &def)=0;
 	// If returns CONTENT_IGNORE, could not allocate id
 	virtual content_t allocateDummy(const std::string &name)=0;
+	// Remove a node
+	virtual void removeNode(const std::string &name)=0;
 
 	/*
 		Update item alias mapping.
diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp
index 5381cba7616c0c62378372d4e57b3273e5b17c83..ff0baea14ee6bab42ba1c18bffee1e154c312cbe 100644
--- a/src/script/lua_api/l_item.cpp
+++ b/src/script/lua_api/l_item.cpp
@@ -525,6 +525,27 @@ int ModApiItemMod::l_register_item_raw(lua_State *L)
 	return 0; /* number of results */
 }
 
+// unregister_item(name)
+int ModApiItemMod::l_unregister_item_raw(lua_State *L)
+{
+	NO_MAP_LOCK_REQUIRED;
+	std::string name = luaL_checkstring(L, 1);
+
+	IWritableItemDefManager *idef =
+			getServer(L)->getWritableItemDefManager();
+
+	// Unregister the node
+	if (idef->get(name).type == ITEM_NODE) {
+		IWritableNodeDefManager *ndef =
+			getServer(L)->getWritableNodeDefManager();
+		ndef->removeNode(name);
+	}
+
+	idef->unregisterItem(name);
+
+	return 0; /* number of results */
+}
+
 // register_alias_raw(name, convert_to_name)
 int ModApiItemMod::l_register_alias_raw(lua_State *L)
 {
@@ -570,6 +591,7 @@ int ModApiItemMod::l_get_name_from_content_id(lua_State *L)
 void ModApiItemMod::Initialize(lua_State *L, int top)
 {
 	API_FCT(register_item_raw);
+	API_FCT(unregister_item_raw);
 	API_FCT(register_alias_raw);
 	API_FCT(get_content_id);
 	API_FCT(get_name_from_content_id);
diff --git a/src/script/lua_api/l_item.h b/src/script/lua_api/l_item.h
index 0f9e4ba9bdfbdd0bb9d94a0b12b66b73caba82a8..be919b70193e60f56ae5b4722d5fdafb555216a9 100644
--- a/src/script/lua_api/l_item.h
+++ b/src/script/lua_api/l_item.h
@@ -135,6 +135,7 @@ class LuaItemStack : public ModApiBase {
 class ModApiItemMod : public ModApiBase {
 private:
 	static int l_register_item_raw(lua_State *L);
+	static int l_unregister_item_raw(lua_State *L);
 	static int l_register_alias_raw(lua_State *L);
 	static int l_get_content_id(lua_State *L);
 	static int l_get_name_from_content_id(lua_State *L);