diff --git src/simutrans/builder/brueckenbauer.cc src/simutrans/builder/brueckenbauer.cc
index a7cf0402b..5d38a7465 100644
--- src/simutrans/builder/brueckenbauer.cc
+++ src/simutrans/builder/brueckenbauer.cc
@@ -916,13 +916,11 @@ void bridge_builder_t::build_ramp(player_t* player, koord3d end, ribi_t::ribi ri
 
 
 
-const char *bridge_builder_t::remove(player_t *player, koord3d pos_start, waytype_t wegtyp)
+const char *bridge_builder_t::get_bridge_tiles(slist_tpl<koord3d>& part_list, slist_tpl<koord3d>& end_list, player_t *player, koord3d pos_start, waytype_t wegtyp, bool must_be_free)
 {
 	marker_t& marker = marker_t::instance(welt->get_size().x, welt->get_size().y);
-	slist_tpl<koord3d> end_list;
-	slist_tpl<koord3d> part_list;
 	slist_tpl<koord3d> tmp_list;
-	const char    *msg;
+	const char *msg;
 
 	tmp_list.insert(pos_start);
 	marker.mark(welt->lookup(pos_start));
@@ -989,12 +987,14 @@ const char *bridge_builder_t::remove(player_t *player, koord3d pos_start, waytyp
 		else if(from->ist_bruecke()) {
 			part_list.insert(pos);
 		}
-		// can we delete everything there?
-		msg = from->kann_alle_obj_entfernen(player);
+		if (must_be_free) {
+			// can we delete everything there?
+			msg = from->kann_alle_obj_entfernen(player);
 
-		if(msg != NULL  ||  (from->get_halt().is_bound()  &&  from->get_halt()->get_owner()!=player)) {
-			simachievements_t::set_achievement(ACH_TOOL_REMOVE_BUSY_BRIDGE);
-			return "Die Bruecke ist nicht frei!\n";
+			if(msg != NULL  ||  (from->get_halt().is_bound()  &&  from->get_halt()->get_owner()!=player)) {
+				simachievements_t::set_achievement(ACH_TOOL_REMOVE_BUSY_BRIDGE);
+				return "Die Bruecke ist nicht frei!\n";
+			}
 		}
 
 		// search neighbors
@@ -1008,8 +1008,143 @@ const char *bridge_builder_t::remove(player_t *player, koord3d pos_start, waytyp
 		}
 	} while (!tmp_list.empty());
 
+	return NULL;
+}
+
+
+bool bridge_builder_t::check_owner(const player_t *owner, const player_t *test)
+{
+	return owner==NULL  ||  owner==test  ||  owner==welt->get_public_player()  ||  test==welt->get_public_player();
+}
+
+
+const char *bridge_builder_t::renovate(player_t *player, koord3d pos_start, waytype_t wegtyp, const bridge_desc_t *desc)
+{
+	if (wegtyp != desc->get_waytype()) {
+		return "";
+	}
+	slist_tpl<koord3d> part_list;
+	slist_tpl<koord3d> end_list;
+	const char *msg;
+
+	msg = get_bridge_tiles(part_list, end_list, player, pos_start, wegtyp, 0);
+	if (msg) {
+		return msg;
+	}
+
+	// Check whether we can replace the ends
+	for (koord3d& pos : end_list) {
+		grund_t *gr = welt->lookup(pos);
+		if (gr->ist_karten_boden()) {
+			const slope_t::type slope = gr->get_grund_hang();
+			if(desc->get_end(slope, slope, gr->get_weg_hang()) == IMG_EMPTY) {
+				return "[TODO] The gradient does not fit a bridge?";
+			}
+		}
+	}
+	// Check whether the bridge would be too long
+	if (desc->get_max_length() > 0  &&  part_list.get_count() > desc->get_max_length()) {
+		return "Bridge is too long for this type!\n";
+	}
+	// Check whether the bridge would be too tall
+	for (koord3d& pos : part_list) {
+		if (desc->get_max_height() > 0) {
+			// check for height
+			grund_t* gr = welt->lookup_kartenboden(pos.get_2d());
+			if (gr  &&  pos.z - gr->get_hoehe() > desc->get_max_height()) {
+				return "bridge is too high for its type!";
+			}
+		}
+	}
+
+	while (!end_list.empty()) {
+		part_list.insert(end_list.remove_first());
+	}
+	// Check scenario and ownership
+	for (koord3d& pos : part_list) {
+		if (const char* error_msg = welt->get_scenario()->is_work_allowed_here(player, TOOL_BUILD_BRIDGE | GENERAL_TOOL, desc->get_finance_waytype(), desc->get_name(), pos)) {
+			return error_msg;
+		}
+		if (!check_owner(welt->lookup(pos)->find<bruecke_t>()->get_owner(), player)) {
+			return "Das Feld gehoert\neinem anderen Spieler\n";
+		}
+	}
+	// All clear now, on to renovation!
+
+	koord3d pos;
+	const way_desc_t *way_desc = way_builder_t::weg_search(desc->get_waytype(), desc->get_topspeed(), welt->get_timeline_year_month(), type_flat);
+	while (!part_list.empty()) {
+		pos = part_list.remove_first();
+		grund_t *gr = welt->lookup(pos);
+		bruecke_t *br = gr->find<bruecke_t>();
+		const bridge_desc_t *br_desc = br->get_desc();
+		if (desc == br_desc) {
+			continue;
+		}
+
+		if (wegtyp != powerline_wt) {
+			weg_t *weg = gr->get_weg(wegtyp);
+			weg->set_owner(player);
+			weg->set_desc(way_desc);
+			weg->set_max_speed(desc->get_topspeed());
+			// respect max speed of catenary
+			wayobj_t const* const wo = gr->get_wayobj(desc->get_wtyp());
+			if (wo  &&  wo->get_desc()->get_topspeed() < weg->get_max_speed()) {
+				weg->set_max_speed( wo->get_desc()->get_topspeed() );
+			}
+		}
+		player_t::add_maintenance(br->get_owner(), -br_desc->get_maintenance(), desc->get_finance_waytype());
+		br->set_owner(player);
+		br->set_desc(desc);
+		player_t::add_maintenance(player, desc->get_maintenance(), desc->get_finance_waytype());
+		player_t::book_construction_costs(player, -desc->get_price(), br->get_pos().get_2d(), desc->get_waytype());
+		gr->calc_image();
+
+		// Now for pillars
+		grund_t *gr_bottom = welt->lookup_kartenboden(pos.get_2d());
+		sint16 height = pos.z - gr_bottom->get_pos().z;
+		ribi_t::ribi ribi = gr->get_weg_ribi_unmasked(wegtyp);
+
+		while (obj_t* const p = gr_bottom->find<pillar_t>()) {
+			p->cleanup(p->get_owner());
+			delete p;
+		}
+		if(desc->get_pillar() > 0  &&  !gr->ist_karten_boden()) {
+			koord zv ((ribi_t::ribi)(ribi & ribi_t::northeast));
+			// make a new pillar here
+			if(desc->get_pillar() == 1  ||  (pos.x*zv.x+pos.y*zv.y)%desc->get_pillar() == 0) {
+//DBG_MESSAGE("bool bridge_builder_t::renovate()","h1=%i, h2=%i",pos.z,gr->get_pos().z);
+				while(height-->0) {
+					if( TILE_HEIGHT_STEP*height <= 127) {
+						// eventual more than one part needed, if it is too high ...
+						gr_bottom->obj_add( new pillar_t(gr_bottom->get_pos(), player, desc, desc->get_pillar(ribi), TILE_HEIGHT_STEP*height) );
+					}
+				}
+			}
+		}
+
+	}
+	welt->set_dirty();
+	
+	return NULL;
+}
+
+
+
+const char *bridge_builder_t::remove(player_t *player, koord3d pos_start, waytype_t wegtyp)
+{
+	slist_tpl<koord3d> part_list;
+	slist_tpl<koord3d> end_list;
+	const char *msg;
+
+	msg = get_bridge_tiles(part_list, end_list, player, pos_start, wegtyp, 1);
+	if (msg) {
+		return msg;
+	}
+
 	// now delete the bridge
 	bool first = true;
+	koord3d pos;
 	while (!part_list.empty()) {
 		pos = part_list.remove_first();
 
diff --git src/simutrans/builder/brueckenbauer.h src/simutrans/builder/brueckenbauer.h
index 7df78cde4..191362fa2 100644
--- src/simutrans/builder/brueckenbauer.h
+++ src/simutrans/builder/brueckenbauer.h
@@ -11,6 +11,8 @@
 #include "../dataobj/koord.h"
 #include "../dataobj/koord3d.h"
 
+#include "../tpl/slist_tpl.h"
+
 class bridge_desc_t;
 class grund_t;
 class karte_ptr_t;
@@ -31,6 +33,9 @@ private:
 
 	static karte_ptr_t welt;
 
+	// allowed owner?
+	static bool check_owner(const player_t *owner, const player_t *test);
+
 	static bool is_blocked(koord3d pos, ribi_t::ribi check_ribi, const char *&error_msg);
 	static bool is_monorail_junction(koord3d pos, player_t *player, const bridge_desc_t *desc, const char *&error_msg);
 
@@ -121,10 +126,25 @@ public:
 	 */
 	static const bridge_desc_t *get_desc(const char *name);
 
+	/**
+	 * Fills in part_list and end_list with the tiles from the bridge at pos_start.
+	 */
+	static const char *get_bridge_tiles(slist_tpl<koord3d>& part_list, slist_tpl<koord3d>& end_list, player_t *player, koord3d pos_start, waytype_t wegtyp, bool must_be_free);
+
+	/**
+	 * Renovates a bridge
+	 * @param player the renovator and owner of the bridge
+	 * @param pos position anywhere on a bridge
+	 * @param wegtyp way type of the bridge
+	 * @param desc descriptor for the new bridge
+	 * @return An error message if the bridge could not be renovated, NULL otherwise
+	 */
+	static const char *renovate(player_t *player, koord3d pos, waytype_t wegtyp, const bridge_desc_t *desc);
+
 	/**
 	 * Removes a bridge
 	 * @param player the demolisher and owner of the bridge
-	 * @param pos position anywhere on a bridge.
+	 * @param pos position anywhere on a bridge
 	 * @param wegtyp way type of the bridge
 	 * @return An error message if the bridge could not be removed, NULL otherwise
 	 */
diff --git src/simutrans/obj/bruecke.h src/simutrans/obj/bruecke.h
index c64b27cf6..2f6d4b9be 100644
--- src/simutrans/obj/bruecke.h
+++ src/simutrans/obj/bruecke.h
@@ -36,6 +36,7 @@ public:
 	 */
 	waytype_t get_waytype() const OVERRIDE { return desc ? desc->get_waytype() : invalid_wt; }
 
+	void set_desc(const bridge_desc_t *b) { desc = b; }
 	const bridge_desc_t *get_desc() const { return desc; }
 
 	// we will always replace first way image
diff --git src/simutrans/tool/simtool.cc src/simutrans/tool/simtool.cc
index 0b31d37a8..07276e7b2 100644
--- src/simutrans/tool/simtool.cc
+++ src/simutrans/tool/simtool.cc
@@ -2965,6 +2965,16 @@ const char *tool_build_bridge_t::do_work( player_t *player, const koord3d &start
 		bridge_builder_t::build_bridge( player, start, end, zv, bridge_height, desc, way_builder_t::weg_search(desc->get_waytype(), desc->get_topspeed(), welt->get_timeline_year_month(), type_flat));
 		return NULL; // all checks are performed before building.
 	}
+	else {
+		grund_t *gr = welt->lookup(start);
+		if (gr && gr->ist_bruecke()) {
+			// Renovate whole bridge
+			weg_t *w = gr->get_weg_nr(0);
+			if (w  &&  w->get_waytype() == desc->get_waytype()) {
+				return bridge_builder_t::renovate(player, start, w->get_waytype(), desc);
+			}
+		}
+	}
 	return "";
 }
 
@@ -3111,6 +3121,13 @@ uint8 tool_build_bridge_t::is_valid_pos(  player_t *player, const koord3d &pos,
 	if (!bridge_builder_t::check_start_tile(player, gr, is_first_click()?0:ribi_type(pos-start), desc)) {
 		return 2;
 	}
+	if (gr->get_typ() == grund_t::brueckenboden) {
+		// Possibly a bridge to update here, but check waytype
+		weg_t *w = gr->get_weg_nr(0);
+		if (w  &&  w->get_waytype() == desc->get_waytype()) {
+			return 1;
+		}
+	}
 	return 0;
 }
 
