I'd like to give a bit of background for this answer first: I'm from Germany, where you can learn software development as an apprenticeship1 in a company and at school over a time of three years while being paid. This is the usual way to enter the industry, while studying CS is less common for devs. I have been working as a trainer on the company side for several year, with apprentices in an age range of 20 to 25, mostly without former training.
I will therefore focus on the training part. Whether you should invest a lot of time or not is not part of this answer. Talk to your manager for that.
Let me first look at what you have written and give some feedback. I will pick up on it afterwards.
[...] but he seems to mostly copy-paste code from tutorials without understanding what it's doing.
[...]
His approach to solving a problem is to keep trying random things until something works [...]
There are a lot of people that get their job done like this, especially if it's just the operations side of a sysadmin. Simply doing step-by-step stuff is a good way to operate, if you don't need to plan ahead. In professional software development of course that approach doesn't work. You know that, but he might not have understood it yet. It is hard to learn, but harder to unlearn behavior.
we often have to remind him multiple times to do a sub-task or implement feedback we've given him on a pull request
ability to retain information
It might be that his tasks are too complex. He is junior without formal training in development, and the working environment might well be quite different from what he is used to.
a lot of time spent explaining things to him feels like it was a waste, because he doesn't seem to retain the information and repeats the mistakes.
That sounds like he gets too much information at the same time and is not able to remember it all. As has already been said in other answers, he needs stuff to be written down. He should be taking notes if you are telling him stuff, but if he doesn't maybe giving him a nudge in that direction might help. Alternatively, you can do the advice in writing. If you want to make that a bit more official, cc your manager in those emails.
He either isn't paying attention, is pretending to understand when he doesn't, or is very forgetful: he keeps writing code with the same bad practices that we've been trying to explain why he shouldn't use.
Now we are getting to the core. He is insecure and knows that he is lacking skill. Maybe he is intimidated by your or your teams knowledge nad the way you treat problems that seem overly complex and hard for him. You have a lot of experience, so many things are easy for you.
Depending on the way your team is structured, I would like to suggest a few things. Let's call the junior Bob for the time being.
Whoever is assigning tickets to Bob should make sure that those are small enough to be done in a day.
If you're doing scrum, that might be the product owner or product manager. It might also be you as a senior dev or team lead. This way, Bob will feel like he has achieved something every day. Nothing is more frustrating and demotivating than being overwhelmed by a task.
Work with him, split it up, but don't use subtasks if he tends to forget them. Simply make smaller tickets. In time, he will get better and can have larger chunks of work. Begin with assigning very easy stuff. It might sound like you can do it in five minutes, but he will need a day. But if it's done at the end of the day that's fine. He will feel like he got something done, and be happy about it.
Don't just review Bob's pull requests and write back feedback. Have a regular code review session every day or whenever a ticket is done. Sit down with him and let him explain the code he wrote. That way you can identify if he is lacking basic skills, like what loop to use for what, or how data structures work. If you don't have time for that, take turns with other senior devs. This will help unlearn the "copy and try stuff until it works" mentality, as it is now required to understand.
Pair-program with him, or let him do pair-programming with other juniors (or people that have recently been junior). That way he will pick up things from others, because it's not just talking. He will see that those things work, so he can adapt and learn them better.
Assign him a part of existing code to read and analyse. Afterwards, sit down with him and let him explain the code. A good way is to couple that with writing documentation or tests for existing code. But only use this sparringly as it can be very boring and also frustrating.
Make him feel part of the team! If you go for a beer with the guys after work, take Bob along. He will not feel comfortable to ask you questions if he only knows you as the senior guy who knows everything and is always disappointed.
Make use of his sys-admin knowledge. Your computer doesn't work? Ask for his help! He will feel appreciated and open up more towards you.
If Bob doesn't understand the ticket structure, try letting him write his own tickets. You can sit down with him and let him define the desired outcome. Write down a few acceptance criteria for the ticket, what test coverage there should be and so on. He will feel more secure if it's clear what he needs to do.
Always tell him where to find you if he needs your help. If you're in an open plan office, he will know you're at your desk, but he might be afraid to approach you. "If you need anything, just come to my desk or drop me a chat message" can go a long way. "Oh and if I'm wearing headphones that's just because the guy next to me is using this loud mechanical keyboard. Just come over anyway if you have a question". Encouragement is important. Try to incorporate that kind of thing into every new task. Remind him he is not on his own, and asking is not bad.
1) This is called Ausbildung zum Fachinformatiker/Anwendungsentwicklung in German