psql ^C takes long time to cancel query
I usually see this when the resultset is large, and has already started to be sent to the client.  The client (apparently, I have not dug into the source code of this) still needs to read everything that was in the pipeline to be sent to it but not yet received, and this can take a long time, especially if the client is in the midst of a swap storm.

Are you using any third party or little-used extensions?

If these aren't the case for you, you will need to provide a reproducer or do some investigation of your own.  While you wait for the cancel to take effect, what is busy on your system?  Just the psql process itself, just the postgres backend it was connected to, or both?  Can you run perf on the busy process and see what it is doing?  Or attach gdb to it and get some backtraces at random times?