Waters was born in Epsom and began his career with Crewe Alexandra. After progressing through the club's academy, he was called up to the first-team by manager Steve Davis in October 2012. Davis explained his decision to promote Waters to the first team, citing his impressive displays in the club's academy. He was an unused substitute five times throughout the 2012–13 season, before signing his first professional contract on a one-year deal in May 2013. Waters suffered a knee injury during a pre-season friendly match and despite recovering, spent the first half of the 2013–14 season playing in the club's reserves. He made his professional debut on 26 November, in a 2–1 defeat at Carlisle United, entering the game as a 59th-minute substitute for Mark Ellis. He made his first start on 8 March, and provided an assist for Chuks Aneke, in a 4–2 defeat at Peterborough United. He signed a new two-year contract in June 2014. Turning 20 early in the 2014–15 season, he stated that his aim was to establish himself in the first-team and he switched shirt number from 29 to 17. Waters made a perfect start to the campaign when he scored his first goal for the "Railwaymen" and set up another goal in a 2–0 win over Barnsley in the first round of the League Cup on 12 August. He scored against the same team four days later in a League One fixture at Gresty Road, though Crewe lost 2–1. His third goal came on 13 September, in a 1–1 draw at Yeovil Town. However he then suffered a dip in form and lost his place in the first-team, ending the campaign with three goals in 21 league and cup appearances, as loan signings Nicky Ajose, Uche Ikpeazu and Lauri Dalla Valle were all preferred. Despite having a year left on his contract, he was released by the club on 8 May 2015.
Cheltenham Town
On 29 June 2015, Waters joined Cheltenham Town on a one-year contract. He impressed in pre-season and scored a brace in a win against Bristol Rovers. He made his debut for the "Robins" on 8 August, in a 1–1 draw at Lincoln City. He scored his first goals on 12 September, in a 3–2 win over Dover Athletic at Whaddon Road. He then scored three goals in four games between 3 October and 13 October against Halifax Town, Braintree Town and Bromley. Later in the season, he scored braces against Guiseley, Southport and Chester. Cheltenham secured promotion as champions of the National League at the end of the season, marking an immediate return to the English Football League after relegation at the end of the 2014–15 season. The Gloucestershire Echo rated Waters 7 out of 10 for the 2015–16 season. He signed a contract extension with the club in May. He scored 16 goals in 55 appearances as Cheltenham secured their League Two status with a 21st-place finish at the end of the 2016–17 campaign. Waters was voted as the club's Player of the Year and was also named as Players' Player and Young Player of the Year. He was offered a new contract by manager Gary Johnson but Waters rejected the offer in search of a new club.
Northampton Town
On 8 June 2017, Waters signed a three-year contract at Northampton Town after manager Justin Edinburgh authorised an undisclosed transfer fee to Cheltenham. However Edinburgh left Sixfields after the "Cobblers" lost the opening four games of the League One season, and his successor, Jimmy Floyd Hasselbaink played Waters out of position. On 12 January 2018, Waters joined League Two club Cambridge United on loan until the end of the 2017–18 season. Manager Shaun Derry had promised to play him in his natural position as a striker. Waters scored his first goal of the season on 17 February, in a 3–1 win over Grimsby Town at the Abbey Stadium, in what was caretaker-manager Joe Dunne's first win in charge. He scored his second goal for the "U's" on the final day of the season, a 5–0 home win over Port Vale, which coincidentally was Dunne's first game in charge following his appointment as the club's new permanent manager. He was one of 3 transfer-listed by Northampton at the end of the 2018–19 season; a further 8 were released. On 7 January 2020 Waters joined Newport County on loan until the end of the 2019–20 season. He made his debut for Newport County on 18 January 2020 in the 2-0 League Two win against Swindon Town as a second-half substitute.
International career
Waters was placed on the stand-by list for Wales under-21s on two occasions, but did not receive a cap. In March 2016, Waters was called up to the England C squad.
Personal life
In addition to football, Waters is also a talented singer.