Further digging through my install revealed that in the database the used_ports table had 36108 entries recording every port from 30001 up to 66109 in use.
The session table didn't have anywhere near that many sessions recorded as in use, so I ran a
"delete from used_ports where session_id not in (select session_id from sessions);" which removed 34683 rows from the table.
My clients are now getting ports in a much more sensible range provided back from the x2goserver when establishing a connection.
Reading the database creation code it looks like there should be a trigger deletes from used_ports when a session table row is removed so I think my database might have somehow failed to create that trigger on creation? Still digging into exactly how the data got into the state it was in.