diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 01763fd73e93a174adfa8088ee675cf7ff5068ad..03f2dad321abce8b44aa639b046ccbb52e2e5649 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -3885,6 +3885,9 @@ Definition tables
         size = 1,
         collisiondetection = false,
     --  ^ collisiondetection: if true collides with physical objects
+        collision_removal = false,
+    --  ^ collision_removal: if true then particle is removed when it collides,
+    --  ^ requires collisiondetection = true to have any effect
         vertical = false,
     --  ^ vertical: if true faces player using y axis only
         texture = "image.png",
@@ -3914,6 +3917,9 @@ Definition tables
     --  ^ minsize/maxsize, minexptime/maxexptime (expirationtime)
         collisiondetection = false,
     --  ^ collisiondetection: if true uses collision detection
+        collision_removal = false,
+    --  ^ collision_removal: if true then particle is removed when it collides,
+    --  ^ requires collisiondetection = true to have any effect
         vertical = false,
     --  ^ vertical: if true faces player using y axis only
         texture = "image.png",
diff --git a/src/client.h b/src/client.h
index cdadb9d3ea42b1f2566f0a48fcb3524a1477345c..a7eb22ad945160d3cf451bc2afdd157eaca6e3b5 100644
--- a/src/client.h
+++ b/src/client.h
@@ -182,6 +182,7 @@ struct ClientEvent
 			f32 expirationtime;
 			f32 size;
 			bool collisiondetection;
+			bool collision_removal;
 			bool vertical;
 			std::string *texture;
 		} spawn_particle;
@@ -199,6 +200,7 @@ struct ClientEvent
 			f32 minsize;
 			f32 maxsize;
 			bool collisiondetection;
+			bool collision_removal;
 			bool vertical;
 			std::string *texture;
 			u32 id;
diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp
index 0498f4048eb7bd1a2e916c97ce1a5e6baaa3a45e..48c573da594ae77977c7336b732bed57e2527557 100644
--- a/src/network/clientpackethandler.cpp
+++ b/src/network/clientpackethandler.cpp
@@ -898,8 +898,10 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
 	bool collisiondetection = readU8(is);
 	std::string texture     = deSerializeLongString(is);
 	bool vertical           = false;
+	bool collision_removal  = false;
 	try {
 		vertical = readU8(is);
+		collision_removal = readU8(is);
 	} catch (...) {}
 
 	ClientEvent event;
@@ -910,6 +912,7 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
 	event.spawn_particle.expirationtime     = expirationtime;
 	event.spawn_particle.size               = size;
 	event.spawn_particle.collisiondetection = collisiondetection;
+	event.spawn_particle.collision_removal  = collision_removal;
 	event.spawn_particle.vertical           = vertical;
 	event.spawn_particle.texture            = new std::string(texture);
 
@@ -942,8 +945,11 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
 	*pkt >> id;
 
 	bool vertical = false;
+	bool collision_removal = false;
 	try {
 		*pkt >> vertical;
+		*pkt >> collision_removal;
+
 	} catch (...) {}
 
 	ClientEvent event;
@@ -961,6 +967,7 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
 	event.add_particlespawner.minsize            = minsize;
 	event.add_particlespawner.maxsize            = maxsize;
 	event.add_particlespawner.collisiondetection = collisiondetection;
+	event.add_particlespawner.collision_removal  = collision_removal;
 	event.add_particlespawner.vertical           = vertical;
 	event.add_particlespawner.texture            = new std::string(texture);
 	event.add_particlespawner.id                 = id;
diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h
index 177b97680e46b5f2641c1e82349b8e3d7c095b6c..3a9483efbfa15c0fd8a34845ed2319aef1da5398 100644
--- a/src/network/networkprotocol.h
+++ b/src/network/networkprotocol.h
@@ -474,6 +474,7 @@ enum ToClientCommand
 		u8 bool vertical
 		u32 len
 		u8[len] texture
+		u8 collision_removal
 	*/
 
 	TOCLIENT_ADD_PARTICLESPAWNER = 0x47,
@@ -495,6 +496,7 @@ enum ToClientCommand
 		u32 len
 		u8[len] texture
 		u32 id
+		u8 collision_removal
 	*/
 
 	TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY = 0x48,
diff --git a/src/particles.cpp b/src/particles.cpp
index 525258a25fa21f08b35b146900fc192eb5cb8c86..ccca691d17d76267f386c7f91b801e1d922dbc74 100644
--- a/src/particles.cpp
+++ b/src/particles.cpp
@@ -54,6 +54,7 @@ Particle::Particle(
 	float expirationtime,
 	float size,
 	bool collisiondetection,
+	bool collision_removal,
 	bool vertical,
 	video::ITexture *texture,
 	v2f texpos,
@@ -85,6 +86,7 @@ Particle::Particle(
 	m_player = player;
 	m_size = size;
 	m_collisiondetection = collisiondetection;
+	m_collision_removal = collision_removal;
 	m_vertical = vertical;
 
 	// Irrlicht stuff
@@ -126,20 +128,21 @@ void Particle::render()
 void Particle::step(float dtime)
 {
 	m_time += dtime;
-	if (m_collisiondetection)
-	{
+	if (m_collisiondetection) {
 		aabb3f box = m_collisionbox;
-		v3f p_pos = m_pos*BS;
-		v3f p_velocity = m_velocity*BS;
-		collisionMoveSimple(m_env, m_gamedef,
-			BS*0.5, box,
-			0, dtime,
-			&p_pos, &p_velocity, m_acceleration * BS);
-		m_pos = p_pos/BS;
-		m_velocity = p_velocity/BS;
-	}
-	else
-	{
+		v3f p_pos = m_pos * BS;
+		v3f p_velocity = m_velocity * BS;
+		collisionMoveResult r = collisionMoveSimple(m_env,
+			m_gamedef, BS * 0.5, box, 0, dtime, &p_pos,
+			&p_velocity, m_acceleration * BS);
+		if (m_collision_removal && r.collides) {
+			// force expiration of the particle
+			m_expiration = -1.0;
+		} else {
+			m_pos = p_pos / BS;
+			m_velocity = p_velocity / BS;
+		}
+	} else {
 		m_velocity += m_acceleration * dtime;
 		m_pos += m_velocity * dtime;
 	}
@@ -210,8 +213,8 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
 	u16 amount, float time,
 	v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
 	float minexptime, float maxexptime, float minsize, float maxsize,
-	bool collisiondetection, bool vertical, video::ITexture *texture, u32 id,
-	ParticleManager *p_manager) :
+	bool collisiondetection, bool collision_removal, bool vertical,
+	video::ITexture *texture, u32 id, ParticleManager *p_manager) :
 	m_particlemanager(p_manager)
 {
 	m_gamedef = gamedef;
@@ -230,6 +233,7 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
 	m_minsize = minsize;
 	m_maxsize = maxsize;
 	m_collisiondetection = collisiondetection;
+	m_collision_removal = collision_removal;
 	m_vertical = vertical;
 	m_texture = texture;
 	m_time = 0;
@@ -277,6 +281,7 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
 					exptime,
 					size,
 					m_collisiondetection,
+					m_collision_removal,
 					m_vertical,
 					m_texture,
 					v2f(0.0, 0.0),
@@ -317,6 +322,7 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
 					exptime,
 					size,
 					m_collisiondetection,
+					m_collision_removal,
 					m_vertical,
 					m_texture,
 					v2f(0.0, 0.0),
@@ -446,6 +452,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
 					event->add_particlespawner.minsize,
 					event->add_particlespawner.maxsize,
 					event->add_particlespawner.collisiondetection,
+					event->add_particlespawner.collision_removal,
 					event->add_particlespawner.vertical,
 					texture,
 					event->add_particlespawner.id,
@@ -480,6 +487,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
 					event->spawn_particle.expirationtime,
 					event->spawn_particle.size,
 					event->spawn_particle.collisiondetection,
+					event->spawn_particle.collision_removal,
 					event->spawn_particle.vertical,
 					texture,
 					v2f(0.0, 0.0),
@@ -555,6 +563,7 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
 		visual_size,
 		true,
 		false,
+		false,
 		texture,
 		texpos,
 		texsize);
diff --git a/src/particles.h b/src/particles.h
index dda84385c1bf49df9571b62823153b26506adf71..bc3ca53b7ce2e14328fc538f9f594c00b44c59ec 100644
--- a/src/particles.h
+++ b/src/particles.h
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 struct ClientEvent;
 class ParticleManager;
+class ClientEnvironment;
 
 class Particle : public scene::ISceneNode
 {
@@ -45,6 +46,7 @@ class Particle : public scene::ISceneNode
 		float expirationtime,
 		float size,
 		bool collisiondetection,
+		bool collision_removal,
 		bool vertical,
 		video::ITexture *texture,
 		v2f texpos,
@@ -97,6 +99,7 @@ class Particle : public scene::ISceneNode
 	float m_size;
 	u8 m_light;
 	bool m_collisiondetection;
+	bool m_collision_removal;
 	bool m_vertical;
 	v3s16 m_camera_offset;
 };
@@ -115,6 +118,7 @@ class ParticleSpawner
 		float minexptime, float maxexptime,
 		float minsize, float maxsize,
 		bool collisiondetection,
+		bool collision_removal,
 		bool vertical,
 		video::ITexture *texture,
 		u32 id,
@@ -148,6 +152,7 @@ class ParticleSpawner
 	video::ITexture *m_texture;
 	std::vector<float> m_spawntimes;
 	bool m_collisiondetection;
+	bool m_collision_removal;
 	bool m_vertical;
 
 };
diff --git a/src/script/lua_api/l_particles.cpp b/src/script/lua_api/l_particles.cpp
index f6c1725de37ef389c06451381f1d4df33e441125..263e35407e36d0312988e155daf08c4ef82c51af 100644
--- a/src/script/lua_api/l_particles.cpp
+++ b/src/script/lua_api/l_particles.cpp
@@ -21,13 +21,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "lua_api/l_internal.h"
 #include "common/c_converter.h"
 #include "server.h"
+#include "particles.h"
 
 // add_particle({pos=, velocity=, acceleration=, expirationtime=,
-// 		size=, collisiondetection=, vertical=, texture=, player=})
+// 		size=, collisiondetection=, collision_removal=, vertical=,
+//		texture=, player=})
 // pos/velocity/acceleration = {x=num, y=num, z=num}
 // expirationtime = num (seconds)
 // size = num
 // collisiondetection = bool
+// collision_removal = bool
 // vertical = bool
 // texture = e.g."default_wood.png"
 int ModApiParticles::l_add_particle(lua_State *L)
@@ -41,8 +44,8 @@ int ModApiParticles::l_add_particle(lua_State *L)
 	float expirationtime, size;
 	expirationtime = size = 1;
 
-	bool collisiondetection, vertical;
-	collisiondetection = vertical = false;
+	bool collisiondetection, vertical, collision_removal;
+	collisiondetection = vertical = collision_removal = false;
 
 	std::string texture = "";
 	std::string playername = "";
@@ -94,12 +97,14 @@ int ModApiParticles::l_add_particle(lua_State *L)
 		size = getfloatfield_default(L, 1, "size", 1);
 		collisiondetection = getboolfield_default(L, 1,
 			"collisiondetection", collisiondetection);
+		collision_removal = getboolfield_default(L, 1,
+			"collision_removal", collision_removal);
 		vertical = getboolfield_default(L, 1, "vertical", vertical);
 		texture = getstringfield_default(L, 1, "texture", "");
 		playername = getstringfield_default(L, 1, "playername", "");
 	}
-	getServer(L)->spawnParticle(playername, pos, vel, acc,
-			expirationtime, size, collisiondetection, vertical, texture);
+	getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, size,
+			collisiondetection, collision_removal, vertical, texture);
 	return 1;
 }
 
@@ -110,6 +115,7 @@ int ModApiParticles::l_add_particle(lua_State *L)
 //				minexptime=, maxexptime=,
 //				minsize=, maxsize=,
 //				collisiondetection=,
+//				collision_removal=,
 //				vertical=,
 //				texture=,
 //				player=})
@@ -117,6 +123,7 @@ int ModApiParticles::l_add_particle(lua_State *L)
 // minexptime/maxexptime = num (seconds)
 // minsize/maxsize = num
 // collisiondetection = bool
+// collision_removal = bool
 // vertical = bool
 // texture = e.g."default_wood.png"
 int ModApiParticles::l_add_particlespawner(lua_State *L)
@@ -129,8 +136,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
 	    minpos= maxpos= minvel= maxvel= minacc= maxacc= v3f(0, 0, 0);
 	float time, minexptime, maxexptime, minsize, maxsize;
 	      time= minexptime= maxexptime= minsize= maxsize= 1;
-	bool collisiondetection, vertical;
-	     collisiondetection= vertical= false;
+	bool collisiondetection, vertical, collision_removal;
+	     collisiondetection = vertical = collision_removal = false;
 	std::string texture = "";
 	std::string playername = "";
 
@@ -189,6 +196,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
 		maxsize = getfloatfield_default(L, 1, "maxsize", maxsize);
 		collisiondetection = getboolfield_default(L, 1,
 			"collisiondetection", collisiondetection);
+		collision_removal = getboolfield_default(L, 1,
+			"collision_removal", collision_removal);
 		vertical = getboolfield_default(L, 1, "vertical", vertical);
 		texture = getstringfield_default(L, 1, "texture", "");
 		playername = getstringfield_default(L, 1, "playername", "");
@@ -201,6 +210,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
 			minexptime, maxexptime,
 			minsize, maxsize,
 			collisiondetection,
+			collision_removal,
 			vertical,
 			texture, playername);
 	lua_pushnumber(L, id);
diff --git a/src/server.cpp b/src/server.cpp
index a3b686c257050027afc6672d8f6a7d86afd31626..ada45dc684fdb2983327bccf0c1ef7177cbdf530 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -1673,7 +1673,8 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
 // Spawns a particle on peer with peer_id
 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
 				float expirationtime, float size, bool collisiondetection,
-				bool vertical, std::string texture)
+				bool collision_removal,
+				bool vertical, const std::string &texture)
 {
 	DSTACK(FUNCTION_NAME);
 
@@ -1683,6 +1684,7 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
 			<< size << collisiondetection;
 	pkt.putLongString(texture);
 	pkt << vertical;
+	pkt << collision_removal;
 
 	if (peer_id != PEER_ID_INEXISTENT) {
 		Send(&pkt);
@@ -1695,7 +1697,8 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
 // Adds a ParticleSpawner on peer with peer_id
 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
 	v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
-	float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
+	float minsize, float maxsize, bool collisiondetection, bool collision_removal,
+	bool vertical, const std::string &texture, u32 id)
 {
 	DSTACK(FUNCTION_NAME);
 
@@ -1708,6 +1711,7 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3
 	pkt.putLongString(texture);
 
 	pkt << id << vertical;
+	pkt << collision_removal;
 
 	if (peer_id != PEER_ID_INEXISTENT) {
 		Send(&pkt);
@@ -3160,7 +3164,8 @@ void Server::notifyPlayers(const std::wstring &msg)
 void Server::spawnParticle(const std::string &playername, v3f pos,
 	v3f velocity, v3f acceleration,
 	float expirationtime, float size, bool
-	collisiondetection, bool vertical, const std::string &texture)
+	collisiondetection, bool collision_removal,
+	bool vertical, const std::string &texture)
 {
 	// m_env will be NULL if the server is initializing
 	if (!m_env)
@@ -3175,13 +3180,15 @@ void Server::spawnParticle(const std::string &playername, v3f pos,
 	}
 
 	SendSpawnParticle(peer_id, pos, velocity, acceleration,
-			expirationtime, size, collisiondetection, vertical, texture);
+			expirationtime, size, collisiondetection,
+			collision_removal, vertical, texture);
 }
 
 u32 Server::addParticleSpawner(u16 amount, float spawntime,
 	v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
 	float minexptime, float maxexptime, float minsize, float maxsize,
-	bool collisiondetection, bool vertical, const std::string &texture,
+	bool collisiondetection, bool collision_removal,
+	bool vertical, const std::string &texture,
 	const std::string &playername)
 {
 	// m_env will be NULL if the server is initializing
@@ -3200,7 +3207,7 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
 	SendAddParticleSpawner(peer_id, amount, spawntime,
 		minpos, maxpos, minvel, maxvel, minacc, maxacc,
 		minexptime, maxexptime, minsize, maxsize,
-		collisiondetection, vertical, texture, id);
+		collisiondetection, collision_removal, vertical, texture, id);
 
 	return id;
 }
diff --git a/src/server.h b/src/server.h
index daf51dee10756b87e2dc8645db73b64cd3c11e84..7ee15a4638a5f1e75975e9ae61cf5e115eed6e5e 100644
--- a/src/server.h
+++ b/src/server.h
@@ -275,7 +275,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
 	void spawnParticle(const std::string &playername,
 		v3f pos, v3f velocity, v3f acceleration,
 		float expirationtime, float size,
-		bool collisiondetection, bool vertical, const std::string &texture);
+		bool collisiondetection, bool collision_removal,
+		bool vertical, const std::string &texture);
 
 	u32 addParticleSpawner(u16 amount, float spawntime,
 		v3f minpos, v3f maxpos,
@@ -283,7 +284,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
 		v3f minacc, v3f maxacc,
 		float minexptime, float maxexptime,
 		float minsize, float maxsize,
-		bool collisiondetection, bool vertical, const std::string &texture,
+		bool collisiondetection, bool collision_removal,
+		bool vertical, const std::string &texture,
 		const std::string &playername);
 
 	void deleteParticleSpawner(const std::string &playername, u32 id);
@@ -456,7 +458,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
 		v3f minacc, v3f maxacc,
 		float minexptime, float maxexptime,
 		float minsize, float maxsize,
-		bool collisiondetection, bool vertical, std::string texture, u32 id);
+		bool collisiondetection, bool collision_removal,
+		bool vertical, const std::string &texture, u32 id);
 
 	void SendDeleteParticleSpawner(u16 peer_id, u32 id);
 
@@ -464,7 +467,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
 	void SendSpawnParticle(u16 peer_id,
 		v3f pos, v3f velocity, v3f acceleration,
 		float expirationtime, float size,
-		bool collisiondetection, bool vertical, std::string texture);
+		bool collisiondetection, bool collision_removal,
+		bool vertical, const std::string &texture);
 
 	u32 SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas);
 	void SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable = true);