diff --git src/base.tab src/base.tab
index 9c76c88b3..ea918cc1c 100644
--- src/base.tab
+++ src/base.tab
@@ -4143,6 +4143,10 @@ name=auto
 note=in exted edit dialogues
 --
 obj=program_text
+name=Priority
+note=label in schedule edit
+--
+obj=program_text
 name=Departures per month
 note=label in schedule edit
 --
@@ -4159,6 +4163,10 @@ name=Max. waiting time
 note=label in schedule edit
 --
 obj=program_text
+name=(priority: %d)
+note=label for schedule entries with priority set
+--
+obj=program_text
 name=No player
 note=text to indicate to use for served by no one
 --
diff --git src/simutrans/dataobj/schedule.cc src/simutrans/dataobj/schedule.cc
index 097b15b23..aead92a2f 100644
--- src/simutrans/dataobj/schedule.cc
+++ src/simutrans/dataobj/schedule.cc
@@ -28,7 +28,7 @@
 #include "../tpl/slist_tpl.h"
 
 
-schedule_entry_t schedule_t::dummy_entry(koord3d::invalid, 0, 0);
+schedule_entry_t schedule_t::dummy_entry(koord3d::invalid, 0, 0, 0);
 
 
 // copy all entries from schedule src to this and adjusts current_stop
@@ -113,14 +113,14 @@ halthandle_t schedule_t::get_prev_halt( player_t *player ) const
 }
 
 
-bool schedule_t::insert(const grund_t* gr, uint8 minimum_loading, uint16 waiting_time )
+bool schedule_t::insert(const grund_t* gr, uint8 minimum_loading, uint16 waiting_time, uint8 priority)
 {
 	// too many stops or wrong kind of stop
 	if (entries.get_count()>=254  ||  !is_stop_allowed(gr)) {
 		return false;
 	}
 
-	entries.insert_at(current_stop, schedule_entry_t(gr->get_pos(), minimum_loading, waiting_time));
+	entries.insert_at(current_stop, schedule_entry_t(gr->get_pos(), minimum_loading, waiting_time, priority));
 	current_stop ++;
 	make_current_stop_valid();
 	return true;
@@ -128,13 +128,13 @@ bool schedule_t::insert(const grund_t* gr, uint8 minimum_loading, uint16 waiting
 
 
 
-bool schedule_t::append(const grund_t* gr, uint8 minimum_loading, uint16 waiting_time)
+bool schedule_t::append(const grund_t* gr, uint8 minimum_loading, uint16 waiting_time, uint8 priority)
 {
 	// too many stops or wrong kind of stop
 	if (entries.get_count()>=254  ||  !is_stop_allowed(gr)) {
 		return false;
 	}
-	entries.append(schedule_entry_t(gr->get_pos(), minimum_loading, waiting_time), 4);
+	entries.append(schedule_entry_t(gr->get_pos(), minimum_loading, waiting_time, priority), 4);
 	return true;
 }
 
@@ -303,7 +303,7 @@ void schedule_t::rdwr(loadsave_t *file)
 			uint32 dummy;
 			pos.rdwr(file);
 			file->rdwr_long(dummy);
-			entries.append(schedule_entry_t(pos, (uint8)dummy, 0));
+			entries.append(schedule_entry_t(pos, (uint8)dummy, 0, 100));
 		}
 	}
 	else {
@@ -311,13 +311,17 @@ void schedule_t::rdwr(loadsave_t *file)
 		for(  uint8 i=0;  i<size;  i++  ) {
 			if(entries.get_count()<=i) {
 				entries.append( schedule_entry_t() );
-				entries[i] .waiting_time = 0;
+				entries[i].waiting_time = 0;
+				entries[i].priority = 100;
 			}
 			entries[i].pos.rdwr(file);
 			file->rdwr_byte(entries[i].minimum_loading);
 			if(file->is_version_atleast(99, 18)) {
 				if( file->is_version_atleast( 122, 1 ) ) {
 					file->rdwr_short(entries[i].waiting_time);
+					if(file->is_version_atleast(124, 4)) {
+						file->rdwr_byte(entries[i].priority);
+					}
 				}
 				else if(file->is_loading()) {
 					uint8 wl=0;
@@ -507,7 +511,7 @@ void schedule_t::sprintf_schedule( cbuffer_t &buf ) const
 {
 	buf.printf("%u|%d|", current_stop, (int)get_type());
 	for(schedule_entry_t const& i : entries) {
-		buf.printf("%s,%i,%i|", i.pos.get_str(), (int)i.minimum_loading, (int)i.waiting_time);
+		buf.printf("%s,%i,%i,%i|", i.pos.get_str(), (int)i.minimum_loading, (int)i.waiting_time, (int)i.priority);
 	}
 }
 
@@ -550,24 +554,24 @@ bool schedule_t::sscanf_schedule( const char *ptr )
 	p++;
 	// now scan the entries
 	while(  *p>0  ) {
-		sint16 values[5];
-		for(  sint8 i=0;  i<5;  i++  ) {
+		sint16 values[6];
+		for(  sint8 i=0;  i<6;  i++  ) {
 			values[i] = atoi( p );
 			while(  *p  &&  (*p!=','  &&  *p!='|')  ) {
 				p++;
 			}
-			if(  i<4  &&  *p!=','  ) {
+			if(  i<5  &&  *p!=','  ) {
 				dbg->error( "schedule_t::sscanf_schedule()","incomplete string!" );
 				return false;
 			}
-			if(  i==4  &&  *p!='|'  ) {
+			if(  i==5  &&  *p!='|'  ) {
 				dbg->error( "schedule_t::sscanf_schedule()","incomplete entry termination!" );
 				return false;
 			}
 			p++;
 		}
 		// ok, now we have a complete entry
-		entries.append(schedule_entry_t(koord3d(values[0], values[1], (sint8)values[2]), (uint8)values[3], (uint16)values[4]));
+		entries.append(schedule_entry_t(koord3d(values[0], values[1], (sint8)values[2]), (uint8)values[3], (uint16)values[4], (uint8)values[5]));
 	}
 	make_valid();
 	return true;
diff --git src/simutrans/dataobj/schedule.h src/simutrans/dataobj/schedule.h
index 50292a0e8..45c94b0c5 100644
--- src/simutrans/dataobj/schedule.h
+++ src/simutrans/dataobj/schedule.h
@@ -145,12 +145,12 @@ public:
 	/**
 	 * Inserts a coordinate at current_stop into the schedule.
 	 */
-	bool insert(const grund_t* gr, uint8 minimum_loading = 0, uint16 waiting_time = 0);
+	bool insert(const grund_t* gr, uint8 minimum_loading = 0, uint16 waiting_time = 0, uint8 priority = 100);
 
 	/**
 	 * Appends a coordinate to the schedule.
 	 */
-	bool append(const grund_t* gr, uint8 minimum_loading = 0, uint16 waiting_time = 0);
+	bool append(const grund_t* gr, uint8 minimum_loading = 0, uint16 waiting_time = 0, uint8 priority = 100);
 
 	/**
 	 * Makes schedule valid for driving:
diff --git src/simutrans/dataobj/schedule_entry.h src/simutrans/dataobj/schedule_entry.h
index 280ab632a..8b22acfc3 100644
--- src/simutrans/dataobj/schedule_entry.h
+++ src/simutrans/dataobj/schedule_entry.h
@@ -19,9 +19,10 @@ struct schedule_entry_t
 public:
 	schedule_entry_t() {}
 
-	schedule_entry_t(koord3d const& pos, uint8 const minimum_loading, uint16 const waiting_time) :
+schedule_entry_t(koord3d const& pos, uint8 const minimum_loading, uint16 const waiting_time, uint8 const priority = 100) :
 		pos(pos),
 		minimum_loading(minimum_loading),
+		priority(priority),
 		waiting_time(waiting_time)
 	{}
 
@@ -37,6 +38,13 @@ public:
 	 */
 	uint8 minimum_loading;
 
+	/**
+	 * Priority for this entry (default 100)
+	 * Freight to stops with higher priority will be loaded by convois
+	 * before freight to stops with lower priority
+	 */
+	uint8 priority;
+
 	/**
 	 * (only active if minimum_loading!=0)
 	 * contains a departing time in ticks, relative to the length of the month
@@ -55,7 +63,7 @@ public:
 
 inline bool operator ==(const schedule_entry_t &a, const schedule_entry_t &b)
 {
-	return a.pos == b.pos  &&  a.minimum_loading == b.minimum_loading  &&  a.waiting_time == b.waiting_time;
+	return a.pos == b.pos  &&  a.minimum_loading == b.minimum_loading  &&  a.waiting_time == b.waiting_time  &&  a.priority == b.priority;
 }
 
 
diff --git src/simutrans/gui/components/gui_schedule.cc src/simutrans/gui/components/gui_schedule.cc
index 60672b9f4..fac3e6452 100644
--- src/simutrans/gui/components/gui_schedule.cc
+++ src/simutrans/gui/components/gui_schedule.cc
@@ -124,6 +124,12 @@ public:
 					stop_extra.buf().append( tick_to_string( starttick+i*delta, true ) );
 				}
 			}
+			if (entry.priority != 100) {
+				if (stop_extra.buf().len() > 0) {
+					stop_extra.buf().append( " " );
+				}
+				stop_extra.buf().printf( translator::translate("(priority: %d)"), entry.priority );
+			}
 		}
 		stop_extra.update();
 		list_dirty = false; // or the first mouseclick will be swallowed!
@@ -409,14 +415,19 @@ gui_schedule_t::gui_schedule_t() :
 		numimp_load.add_listener(this);
 		numimp_load.set_rigid(true);
 		add_component(&numimp_load);
-		new_component<gui_fill_t>();
+		lb_priority_str.set_rigid(true);
+		add_component(&lb_priority_str);
 
 		add_component(&lb_departure_str);
 		lb_departure_str.set_rigid(true);
 		departure.set_rigid(true);
 		departure.add_listener(this);
 		add_component(&departure);
-		new_component<gui_fill_t>();
+		numimp_priority.set_limits( 0, 255 );
+		numimp_priority.set_increment_mode( 10 );
+		numimp_priority.add_listener(this);
+		numimp_priority.set_rigid(true);
+		add_component(&numimp_priority);
 	}
 	end_table();
 
@@ -505,6 +516,7 @@ void gui_schedule_t::init(schedule_t* schedule_, player_t* player, convoihandle_
 		stats->update_schedule(false);
 
 		numimp_load.set_value( schedule->get_current_entry().minimum_loading );
+		numimp_priority.set_value( schedule->get_current_entry().priority );
 
 		// not allow to change entries beyond waiting time
 		no_editing = (convoi_mode.is_bound() && line_mode.is_bound());
@@ -549,8 +561,10 @@ void gui_schedule_t::update_selection()
 {
 	// set all elements invisible first
 	cb_wait.set_visible(false);
+	numimp_priority.set_visible(false);
 	numimp_load.set_visible(false);
 	departure.set_visible(false);
+	lb_priority_str.set_visible(false);
 	lb_load_str.set_visible(false);
 	lb_departure_str.set_visible(false);
 
@@ -561,6 +575,10 @@ void gui_schedule_t::update_selection()
 
 		if(  haltestelle_t::get_halt(schedule->entries[current_stop].pos, player).is_bound()  ) {
 
+			lb_priority_str.set_visible(true);
+			lb_priority_str.set_text("Priority");
+			numimp_priority.set_visible(true);
+			numimp_priority.set_value( schedule->entries[current_stop].priority );
 			cb_wait.set_visible(true);
 			if( schedule->entries[current_stop].get_absolute_departures() ) {
 				cb_wait.set_selection( 1 );
@@ -621,6 +639,12 @@ bool gui_schedule_t::action_triggered( gui_action_creator_t *comp, value_t p)
 		stats->update_schedule(true);
 		update_selection();
 	}
+	else if( comp == &numimp_priority ) {
+		if (!schedule->empty()) {
+			schedule->entries[schedule->get_current_stop()].priority = max( 0, min((uint8)p.i, 255) );
+			update_selection();
+		}
+	}
 	else if( comp == &cb_wait) {
 		if(  p.i==1  &&  schedule->entries[schedule->get_current_stop()].get_absolute_departures()==0  ) {
 			// absolute departure mode
@@ -715,6 +739,7 @@ void gui_schedule_t::draw(scr_coord pos)
 		bt_revert.enable( !is_all_same &&  is_allowed );
 
 		cb_wait.enable( is_allowed );
+		numimp_priority.enable( is_allowed );
 		numimp_load.enable( is_allowed );
 		departure.enable( is_allowed );
 		bt_return.enable( is_allowed );
diff --git src/simutrans/gui/components/gui_schedule.h src/simutrans/gui/components/gui_schedule.h
index e32868cae..d9d801b91 100644
--- src/simutrans/gui/components/gui_schedule.h
+++ src/simutrans/gui/components/gui_schedule.h
@@ -42,7 +42,8 @@ private:
 	// always needed
 	button_t bt_revert, bt_return, bt_remove_double;
 
-	gui_label_t lb_load_str, lb_departure_str;
+	gui_label_t lb_priority_str, lb_load_str, lb_departure_str;
+	gui_numberinput_t numimp_priority;
 	gui_numberinput_t numimp_load;
 	gui_combobox_t cb_wait, insert_mode;
 
diff --git src/simutrans/simconvoi.cc src/simutrans/simconvoi.cc
index 9b4928250..fc4e7c35b 100644
--- src/simutrans/simconvoi.cc
+++ src/simutrans/simconvoi.cc
@@ -2948,6 +2948,8 @@ void convoi_t::hat_gehalten(halthandle_t halt)
 
 	// prepare a list of all destination halts in the schedule
 	vector_tpl<halthandle_t> destination_halts(schedule->get_count());
+	// also record their priorities
+	vector_tpl<uint8> destination_priorities(schedule->get_count());
 	if (!no_load) {
 		const uint8 count = schedule->get_count();
 		bool first_entry = true;
@@ -2979,6 +2981,16 @@ void convoi_t::hat_gehalten(halthandle_t halt)
 					if (!welt->get_settings().is_avoid_overcrowding() || !plan_halt->is_overcrowded(idx)) {
 						// not somebody loaded before us in the queue
 						destination_halts.append(plan_halt);
+						destination_priorities.append(schedule->entries[wrap_i].priority);
+						// now ensure the stop is before any stop with lower priority
+						// (this is a stable sort, so stops of same priority are handled
+						// in the order they are encountered in the schedule)
+						int i = destination_halts.get_count()-1;
+						while (i > 0 && destination_priorities[i-1] < destination_priorities[i]) {
+							std::swap(destination_priorities[i-1], destination_priorities[i]);
+							std::swap(destination_halts[i-1], destination_halts[i]);
+							--i;
+						}
 						all_served_this_stop = false;
 						break;
 					}
