diff --git a/data/cactus_side.png b/data/cactus_side.png
new file mode 100644
index 0000000000000000000000000000000000000000..fc479fde6f9dc859180035ee3974c1ffb198136c
Binary files /dev/null and b/data/cactus_side.png differ
diff --git a/data/cactus_top.png b/data/cactus_top.png
new file mode 100644
index 0000000000000000000000000000000000000000..f9e68df5114b04f48290dc277b9d73f49db941cc
Binary files /dev/null and b/data/cactus_top.png differ
diff --git a/src/map.cpp b/src/map.cpp
index a49de3c4600b3dc4c39d6d7096fde1aa6ffd8917..c48599d475ba5e419e22d2d027db94905dabea3c 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -2045,6 +2045,20 @@ void make_tree(VoxelManipulator &vmanip, v3s16 p0)
 	}
 }
 
+void make_cactus(VoxelManipulator &vmanip, v3s16 p0)
+{
+	MapNode cactusnode(CONTENT_CACTUS);
+
+	s16 trunk_h = 3;
+	v3s16 p1 = p0;
+	for(s16 ii=0; ii<trunk_h; ii++)
+	{
+		if(vmanip.m_area.contains(p1))
+			vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
+		p1.Y++;
+	}
+}
+
 /*
 	Noise functions. Make sure seed is mangled differently in each one.
 */
@@ -3207,18 +3221,24 @@ void makeChunk(ChunkMakeData *data)
 				if(y > y_nodes_max - 6)
 					continue;
 				v3s16 p(x,y,z);
-				/*
-					Trees grow only on mud and grass
-				*/
 				{
 					u32 i = data->vmanip.m_area.index(v3s16(p));
 					MapNode *n = &data->vmanip.m_data[i];
-					if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
+					if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS && n->d != CONTENT_SAND)
 						continue;
+					// Trees grow only on mud and grass
+					if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
+					{
+						p.Y++;
+						make_tree(data->vmanip, p);
+					}
+					// Cactii grow only on sand
+					if(n->d == CONTENT_SAND)
+					{
+						p.Y++;
+						make_cactus(data->vmanip, p);
+					}
 				}
-				p.Y++;
-				// Make a tree
-				make_tree(data->vmanip, p);
 			}
 		}
 		/*u32 tree_max = relative_area / 60;
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index c006b8222ec13e75ebc3c9ad47fc446219927c84..8ceeecfbab1ceb5ae524c7178f7496fa1a7272f0 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -215,6 +215,16 @@ void init_mapnode()
 	}
 	f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
 
+	i = CONTENT_CACTUS;
+	f = &g_content_features[i];
+	f->setAllTextures("cactus_side.png");
+	f->setTexture(0, "cactus_top.png");
+	f->setTexture(1, "cactus_top.png");
+	f->setInventoryTextureCube("cactus_top.png", "cactus_side.png", "cactus_side.png");
+	f->param_type = CPT_MINERAL;
+	f->is_ground_content = true;
+	f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
+
 	i = CONTENT_GLASS;
 	f = &g_content_features[i];
 	f->light_propagates = true;
diff --git a/src/mapnode.h b/src/mapnode.h
index ad256585ff425aaa3c2f232c0fa709546b5bbac0..c4dcbfbe500a6daabddc8dfc7f2abead36db228c 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -102,6 +102,7 @@ void init_content_inventory_texture_paths();
 #define CONTENT_GLASS 20
 #define CONTENT_FENCE 21
 #define CONTENT_SANDSTONE 22
+#define CONTENT_CACTUS 23
 
 /*
 	Content feature list
diff --git a/src/materials.cpp b/src/materials.cpp
index 60c1894bff6a70a4a0bbf061938c5feb6d8a40fc..a1d419562d47089e9b9c056000f44161c7856bf9 100644
--- a/src/materials.cpp
+++ b/src/materials.cpp
@@ -73,6 +73,7 @@ void initializeMaterialProperties()
 	
 	setWoodLikeDiggingProperties(CONTENT_TREE, 1.0);
 	setWoodLikeDiggingProperties(CONTENT_LEAVES, 0.15);
+	setWoodLikeDiggingProperties(CONTENT_CACTUS, 0.75);
 	setWoodLikeDiggingProperties(CONTENT_GLASS, 0.15);
 	setWoodLikeDiggingProperties(CONTENT_FENCE, 0.75);
 	setWoodLikeDiggingProperties(CONTENT_WOOD, 0.75);
diff --git a/src/server.cpp b/src/server.cpp
index c7b64f413eee08fc3b5c77bcacc5e9e213f6c039..994e62eaf63a63e6304141bac2d8747c354c3d32 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -4078,6 +4078,7 @@ void setCreativeInventory(Player *player)
 		CONTENT_SANDSTONE,
 		CONTENT_TREE,
 		CONTENT_LEAVES,
+		CONTENT_CACTUS,
 		CONTENT_GLASS,
 		CONTENT_FENCE,
 		CONTENT_MESE,
diff --git a/src/tile.cpp b/src/tile.cpp
index 8b0c3f2ea155230541ff773cae1834ea90364bb7..2a2d2a70c0b57f35727bcc6c6a35c95b184199af 100644
--- a/src/tile.cpp
+++ b/src/tile.cpp
@@ -513,6 +513,8 @@ void TextureSource::buildMainAtlas()
 	sourcelist.push_back("tree_top.png");
 	sourcelist.push_back("water.png");
 	sourcelist.push_back("leaves.png");
+	sourcelist.push_back("cactus_side.png");
+	sourcelist.push_back("cactus_top.png");
 	sourcelist.push_back("glass.png");
 	sourcelist.push_back("mud.png^grass_side.png");
 	sourcelist.push_back("cobble.png");