The worst problem I've seen with pessimistic locking is the inevitable bottleneck that the database becomes.
In other words provided that your code is preventing deadlocks (as you say in your post) at the app level, performance becomes the problem - throughput drops as only 1 user at a time can perform an update on a given set of data.
It is possible that a locked table remains locked if a system exception occurs such that the select for update
is executed but not committed, but by and large this isn't common (although this obviously depends on your code). I've not seen this happen through an infrastructure related issue though, only through application errors.
You can mitigate the throughput issue somewhat by batching updates if possible, but this really depends on your particular situation.