diff --git a/doc/changelog.txt b/doc/changelog.txt
index 7089146a07a74216970524c370cd56e7513b17b0..e02019783d6242751013ed54968a4ef947f2264a 100644
--- a/doc/changelog.txt
+++ b/doc/changelog.txt
@@ -3,7 +3,7 @@ Minetest-c55 changelog
 This should contain all the major changes.
 For minor stuff, refer to the commit log of the repository.
 
-X:
+2011-05-29:
 - Optimized smooth lighting
 - A number of small fixes
 - Added clouds and simple skyboxes
diff --git a/src/player.cpp b/src/player.cpp
index efb2f34473341910e80d647bc0d21fc4a92f3afa..198eca95706c4a3d8c2f9149af7922cb93a959d3 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -102,7 +102,6 @@ void Player::serialize(std::ostream &os)
 	args.setV3F("position", m_position);
 	args.setBool("craftresult_is_preview", craftresult_is_preview);
 	args.setS32("hp", hp);
-	args.setU64("privs", privs);
 
 	args.writeLines(os);
 
diff --git a/src/player.h b/src/player.h
index 157a25b5b073b75a6fb6b484d3d4676c385a175f..a7a2433ce3d52f10f461c7d349f921958d703e46 100644
--- a/src/player.h
+++ b/src/player.h
@@ -126,9 +126,6 @@ class Player
 
 	u16 hp;
 
-	// Player's privileges - a bitmaps of PRIV_xxxx.
-	u64 privs;
-
 	u16 peer_id;
 
 protected:
diff --git a/src/server.cpp b/src/server.cpp
index 4569d028e7c79addd39b8670b2b22bae59cc90e9..56874c46c3c8442f4c49ffbc23bf1eb3af0b710f 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -2083,7 +2083,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 		if(datasize < 13)
 			return;
 
-		if((player->privs & PRIV_BUILD) == 0)
+		if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
 			return;
 
 		/*
@@ -2167,7 +2167,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 		if(datasize < 7)
 			return;
 
-		if((player->privs & PRIV_BUILD) == 0)
+		if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
 			return;
 
 		/*
@@ -2368,8 +2368,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 			}
 
 			// Make sure the player is allowed to do it
-			if((player->privs & PRIV_BUILD) == 0)
+			if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
+			{
+				dstream<<"Player "<<player->getName()<<" cannot remove node"
+						<<" because privileges are "<<getPlayerPrivs(player)
+						<<std::endl;
 				cannot_remove_node = true;
+			}
 
 			/*
 				If node can't be removed, set block to be re-sent to
@@ -2517,8 +2522,15 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 				try{
 					// Don't add a node if this is not a free space
 					MapNode n2 = m_env.getMap().getNode(p_over);
+					bool no_enough_privs =
+							((getPlayerPrivs(player) & PRIV_BUILD)==0);
+					if(no_enough_privs)
+						dstream<<"Player "<<player->getName()<<" cannot add node"
+							<<" because privileges are "<<getPlayerPrivs(player)
+							<<std::endl;
+
 					if(content_buildable_to(n2.d) == false
-						|| (player->privs & PRIV_BUILD) ==0)
+						|| no_enough_privs)
 					{
 						// Client probably has wrong data.
 						// Set block not sent, so that client will get
@@ -2715,7 +2727,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 #endif
 	else if(command == TOSERVER_SIGNTEXT)
 	{
-		if((player->privs & PRIV_BUILD) == 0)
+		if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
 			return;
 		/*
 			u16 command
@@ -2774,7 +2786,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 	}
 	else if(command == TOSERVER_SIGNNODETEXT)
 	{
-		if((player->privs & PRIV_BUILD) == 0)
+		if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
 			return;
 		/*
 			u16 command
@@ -2952,9 +2964,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 		
 		// Local player gets all privileges regardless of
 		// what's set on their account.
-		u64 privs = player->privs;
-		if(g_settings.get("name") == player->getName())
-			privs = PRIV_ALL;
+		u64 privs = getPlayerPrivs(player);
 
 		// Parse commands
 		std::wstring commandprefix = L"/#";
@@ -4288,9 +4298,6 @@ Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id
 		m_authmanager.setPrivs(name,
 				stringToPrivs(g_settings.get("default_privs")));
 
-		if(g_settings.exists("default_privs"))
-				player->privs = g_settings.getU64("default_privs");
-
 		/*
 			Set player position
 		*/
@@ -4503,6 +4510,23 @@ void Server::handlePeerChanges()
 	}
 }
 
+u64 Server::getPlayerPrivs(Player *player)
+{
+	if(player==NULL)
+		return 0;
+	std::string playername = player->getName();
+	// Local player gets all privileges regardless of
+	// what's set on their account.
+	if(g_settings.get("name") == playername)
+	{
+		return PRIV_ALL;
+	}
+	else
+	{
+		return getPlayerAuthPrivs(playername);
+	}
+}
+
 void dedicated_server_loop(Server &server, bool &kill)
 {
 	DSTACK(__FUNCTION_NAME);
diff --git a/src/server.h b/src/server.h
index a6da801be3be47cd56c09a33b934f36bd99df7bb..7b73e476c54530a563434bea71c00c3b5335a720 100644
--- a/src/server.h
+++ b/src/server.h
@@ -424,7 +424,29 @@ class Server : public con::PeerHandler, public MapEventReceiver,
 
 	// Envlock and conlock should be locked when calling this
 	void SendMovePlayer(Player *player);
+	
+	u64 getPlayerAuthPrivs(const std::string &name)
+	{
+		try{
+			return m_authmanager.getPrivs(name);
+		}
+		catch(AuthNotFoundException &e)
+		{
+			dstream<<"WARNING: Auth not found for "<<name<<std::endl;
+			return 0;
+		}
+	}
 
+	void setPlayerAuthPrivs(const std::string &name, u64 privs)
+	{
+		try{
+			return m_authmanager.setPrivs(name, privs);
+		}
+		catch(AuthNotFoundException &e)
+		{
+			dstream<<"WARNING: Auth not found for "<<name<<std::endl;
+		}
+	}
 
 private:
 
@@ -493,6 +515,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
 	void handlePeerChange(PeerChange &c);
 	void handlePeerChanges();
 
+	u64 getPlayerPrivs(Player *player);
+
 	/*
 		Variables
 	*/
diff --git a/src/servercommand.cpp b/src/servercommand.cpp
index e14f326f40fb28779b9f22b15a611c3bba4cd9fa..e05578b3994d8dbdd56a2626286f4000cf1695d0 100644
--- a/src/servercommand.cpp
+++ b/src/servercommand.cpp
@@ -35,7 +35,8 @@ void cmd_privs(std::wostringstream &os,
 	{
 		// Show our own real privs, without any adjustments
 		// made for admin status
-		os<<L"-!- " + narrow_to_wide(privsToString(ctx->player->privs));
+		os<<L"-!- " + narrow_to_wide(privsToString(
+				ctx->server->getPlayerAuthPrivs(ctx->player->getName())));
 		return;
 	}
 
@@ -52,7 +53,7 @@ void cmd_privs(std::wostringstream &os,
 		return;
 	}
 	
-	os<<L"-!- " + narrow_to_wide(privsToString(tp->privs));
+	os<<L"-!- " + narrow_to_wide(privsToString(ctx->server->getPlayerAuthPrivs(tp->getName())));
 }
 
 void cmd_grantrevoke(std::wostringstream &os,
@@ -83,14 +84,19 @@ void cmd_grantrevoke(std::wostringstream &os,
 		os<<L"-!- No such player";
 		return;
 	}
+	
+	std::string playername = wide_to_narrow(ctx->parms[1]);
+	u64 privs = ctx->server->getPlayerAuthPrivs(playername);
 
 	if(ctx->parms[0] == L"grant")
-		tp->privs |= newprivs;
+		privs |= newprivs;
 	else
-		tp->privs &= ~newprivs;
+		privs &= ~newprivs;
+	
+	ctx->server->setPlayerAuthPrivs(playername, privs);
 	
 	os<<L"-!- Privileges change to ";
-	os<<narrow_to_wide(privsToString(tp->privs));
+	os<<narrow_to_wide(privsToString(privs));
 }
 
 void cmd_time(std::wostringstream &os,